这个题目和hdu4756差不多,是给你一个图,然后是q次改变边的权值,权值只增不减,最后问你每次改变之后的最小树的平均值是多少.
思路:(prim+树形dp)
先跑一边最小树(建议用普利姆,别用克鲁斯卡尔,虽然网上有用k过的,但我感觉理论上会超时 n*n*nlog(n)/2),然后树形dp跑出任意两个集合之间的最有替代边.(n^2),然后当每次输入一条要该边的边的时候,先判断先是不是最小树上的边,如果不是那么sum直接加最小树,如果是那么就用sum - dis[u][v] + min(dis ,dp[u][v]);就是用原边和不用原边的最小值,记住此时的原边权值已经改变....
#include<stdio.h> #include<string.h> #include<algorithm> #define N (3000 + 100) #define inf 9223372036854775807 using namespace std; typedef struct { int to ,next; }STAR; STAR E[N*2]; int list[N] ,tot; double map[N][N]; double dp[N][N]; void add(int a ,int b) { E[++tot].to = b; E[tot].next = list[a]; list[a] = tot; E[++tot].to = a; E[tot].next = list[b]; list[b] = tot; } double minn(double a ,double b) { return a < b ? a : b; } double DFS_T_DP(int p ,int s ,int f) { double now = inf; for(int k = list[s] ;k ;k = E[k].next) { int to = E[k].to; if(to == f) continue; double tmp = DFS_T_DP(p ,to ,s); now = minn(tmp ,now); dp[s][to] = dp[to][s] = minn(dp[s][to] ,tmp); } if(f != p) now = minn(now ,map[p][s]); return now; } struct PRIM //从0开始用 { double d[N];int vis[N]; bool mp[N][N]; //标记最小生成树上的边 double ans;//最小树 int n;//点的个数 记得初始化 *** double dis[N][N]; // 距离 记得初始化 ***** void prim() { for(int i=0;i<n;i++) { vis[i]=0; d[i]=dis[0][i]; } vis[0]=-1; ans=0; memset(mp,0,sizeof(mp)); for(int i=1;i<n;i++) { double Min= inf; int node=-1; for(int j=0;j<n;j++) { if(vis[j]!=-1 && d[j]<Min) { node=j; Min=d[j]; } } ans+=Min; mp[vis[node]][node]=mp[node][vis[node]]=1; add(vis[node],node); // 建树 vis[node]=-1; for(int j=0;j<n;j++) { if(vis[j]!=-1 && d[j]>dis[node][j]) { vis[j]=node; d[j]=dis[node][j]; } } } } }P; int main () { int n ,m ,q ,i ,j ,a ,b; double dis; while(~scanf("%d %d" ,&n ,&m) && n + m) { for(i = 0 ;i <= n ;i ++) { for(j = i + 1 ;j <= n ;j ++) P.dis[i][j] = P.dis[j][i] = map[i][j] = map[j][i] = dp[i][j] = dp[j][i] = inf; P.dis[i][i] = P.dis[i][i] = map[i][i] = map[i][i] = 0; } for(i = 1 ;i <= m ;i ++) { scanf("%d %d %lf" ,&a ,&b ,&dis); map[a][b] = map[b][a] = dis; P.dis[a][b] = P.dis[b][a] = dis; } P.n = n; memset(list ,0 ,sizeof(list)); tot = 1; P.prim(); double T_sum = P.ans; for(i = 0 ;i < n ;i ++) DFS_T_DP(i ,i ,-1); double ans_sum = 0; scanf("%d" ,&q); for(i = 1 ;i <= q ;i ++) { scanf("%d %d %lf" ,&a ,&b ,&dis); double now; if(!P.mp[a][b]) now = T_sum ; else { if(dis > dp[a][b]) now = T_sum - map[a][b] + dp[a][b] ; else now = T_sum - map[a][b] + dis ; } ans_sum += now; } printf("%.4lf " ,ans_sum / q); } return 0; }