先用prim算法求一次最小生成树,最小生成树用链式前向星储存起来,然后树形dp预处理,节点i到子树j的最小距离,每次访问改变一条边的值,删去这条边,这个最小生成树被分为两个子树,dfs求得连接这两个子树的最小权值边,将每次访问后的最小生成树权值加起来除以访问次数即得到平均值,
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> #include <cstring> #include <climits> #include <string> #include <vector> #include <cmath> #include <stack> #include <queue> #include <set> #include <map> #include <sstream> #include <cctype> using namespace std; typedef long long ll; typedef pair<int ,int> pii; #define MEM(a,b) memset(a,b,sizeof a) #define CLR(a) memset(a,0,sizeof a); const int inf = 0x3f3f3f3f; const int MOD = 1e9 + 7; //#define LOCAL int mp[3005][3005]; bool vis[3005]; int to[3005]; int dp[3005][3005]; bool flag[3005][3005]; int pnt[3005*2],nxt[3005*2],head[3005],cost[3005*2]; int n,m; int tmp; int cnt; void addedge(int u,int v,int c){ pnt[cnt]=v; nxt[cnt]=head[u]; cost[cnt]=c; head[u]=cnt++; } int prime(){ int ans = 0; CLR(vis); vis[0]=1; for(int i=1;i<n;i++){ to[i]=0; } for(int i=1;i<n;i++){ int mincost = inf; int pos; for(int j=0;j<n;j++){ if(!vis[j] && mincost > mp[to[j]][j]){ mincost = mp[to[j]][j]; pos = j; } } if(mincost == inf)break; ans += mincost; vis[pos]=1; flag[to[pos]][pos]=1; flag[pos][to[pos]]=1; addedge(to[pos],pos,mincost); addedge(pos,to[pos],mincost); for(int j=0;j<n;j++){ if(!vis[j] && mp[to[j]][j] > mp[pos][j]) to[j]=pos; } } return ans; } int DP(int u,int pre,int root){ dp[root][u]=inf; if(pre != root)dp[root][u]=mp[root][u]; for(int i=head[u];~i;i=nxt[i]){ int v = pnt[i]; if(v != pre){ dp[root][u] = min(dp[root][u],DP(v,u,root)); } } return dp[root][u]; } int solve(int u,int pre,int tree){ int ans = dp[u][tree]; for(int i=head[u];~i;i=nxt[i]){ int v = pnt[i]; if(v!=pre){ ans = min(solve(v,u,tree),ans); } } return ans; } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif while(cin >> n >>m && (n+m)){ double sum = 0; for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ mp[i][j]=inf; flag[i][j]=0; } } cnt = 0; MEM(head,-1); for(int i=1;i<=m;i++){ int u,v,c;scanf("%d%d%d",&u,&v,&c); mp[u][v]=c; mp[v][u]=c; } tmp = prime(); for(int i=0;i<n;i++){ DP(i,-1,i); } int q;scanf("%d",&q); for(int i=1;i<=q;i++){ int u,v,c; scanf("%d%d%d",&u,&v,&c); if(!(flag[u][v])){ sum += tmp; } else{ int x = solve(u,v,v); sum += min(tmp-mp[u][v]+c,tmp-mp[u][v]+x); } } printf("%.4lf\n",sum/q); } return 0; }