题目大意:给你一个无向图,其中有些边有可能增大且每次只增大一条便,每条便增大的可能性相等,问最后产生的最小生成树的期望值为多少。
解题思路:近似与次小生成树的思路,先找一个最小生成树,并找出当生成树中的树边的最佳替代边,
如果增大的边为树边,用增大以后的边和最佳替代边做比较选择性替代,加上新生成树的总边权。
不然就不用做修改,直接加上原树的边权就好。
唯一的难点就是找最佳替代边,之前以为很难,后来发现就那么回事。
把每个点设为树根,然后从下递归回来就好
每递归一次复杂度为(N),总复杂度(N^2)。
代码看一遍就懂了。。。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <utility>
#include <set>
#include <map>
#include <string>
#include <cmath>
using namespace std;
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,l,r) for(int i=(l);i<=(r);++i)
#define DWN(i,r,l) for(int i=(r);i>=(l);--i)
#define pb push_back
#define mp(a,b) make_pair(a,b)
#define N 3100
#define M 6010
#define INF 1e9
vector<int>f[N];
int g[N][N],dp[N][N];
bool visit[N],mst[N][N];
int dis[N],pre[N];
int root;
void init(int n)
{
FOR(i,0,n) f[i].clear();
FOR(i,0,n)
FOR(j,0,n)
dp[i][j]=g[i][j]=INF;
}
int prime(int n)//一般的prime
{
memset(visit,0,sizeof(visit));
memset(mst,0,sizeof(mst));
REP(i,n) dis[i]=g[0][i],pre[i]=0;
visit[0]=1;
dis[n]=INF;
int sum=0;
REP(aa,n-1)
{
int k=n;
REP(i,n) if(!visit[i] && dis[i]<dis[k]) k=i;
visit[k]=1;
f[k].pb(pre[k]);
f[ pre[k] ].pb(k);
sum+=dis[k];
mst[k][ pre[k] ]=mst[ pre[k] ][k]= 1;
REP(i,n) if(!visit[i] && g[k][i]<dis[i]) dis[i]=g[k][i],pre[i]=k;
}
return sum;
}
int dfs(int cur,int fa)//往下递归找最佳替代边
{ //ret表示能从root覆盖到cur点及cur以下的最小边的权值
int ret=INF;
REP(i,(int)f[cur].size())
{
if(f[cur][i]!=fa)
ret=min(ret,dfs(f[cur][i],cur));
}
if(cur!=root && !mst[root][cur])
{
ret=min(ret,g[root][cur]);
}
dp[fa][cur]=dp[cur][fa]=min(dp[cur][fa],ret);
return ret;//这里只能返回ret,不能返回dp[fa][cur]
}
void solve(int n)
{
REP(i,n)//以每个点为根往下递归一次
{
root=i;
dfs(i,i);
}
}
int main()
{
//freopen("in","r",stdin);
int n,m;
int x,y,c;
while(cin>>n>>m && n+m)
{
init(n);
while(m--)
{
scanf("%d%d%d",&x,&y,&c);
g[x][y]=g[y][x]=c;
}
int sum=prime(n);
solve(n);
cin>>m;
long long ans=0;
REP(i,m)
{
scanf("%d%d%d",&x,&y,&c);
if(mst[x][y]) ans+=sum-g[x][y]+min(c,dp[x][y]);//如果是树边,从替代边和增加后的边替代原边
else ans+=sum;//不然就不用管了,直接加上
}
printf("%.4lf\n",(double)ans/m);
}
}