http://acm.split.hdu.edu.cn/showproblem.php?pid=5723
题意:
给出一个无向图,每条路都有一个代价,求出把所有城市连通的最小代价。在此基础上,国王会从这里面随机挑出两个城市作为起点和终点,求出国王要走的路的期望值。
思路:
第一问很简单,最小生成树计算一下即可。
对于第二问,在新图的基础上,考虑每条边所能给出的贡献值。假设这条边两个的点数分别为x和y,那么这条边总的贡献次数就是x*y,贡献值为x*y*w。求两边的点数dfs即可。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const int maxn = 100000 + 5; 16 17 int n, m; 18 double tot; 19 20 struct node 21 { 22 int u,v,w; 23 bool operator< (const node& rhs) const 24 { 25 return w<rhs.w; 26 } 27 }edge[1000005]; 28 29 int p[maxn]; 30 vector<pll> G[maxn]; 31 32 int Find(int x) 33 { 34 return p[x]==x?x:p[x]=Find(p[x]); 35 } 36 37 void Kruskal() 38 { 39 ll sum = 0; 40 int num=0; 41 sort(edge,edge+m); 42 for(int i=0;i<m;i++) 43 { 44 int x = Find(edge[i].u); 45 int y = Find(edge[i].v); 46 if(x!=y) 47 { 48 p[x]=y; 49 sum+=edge[i].w; 50 num++; 51 G[edge[i].u].push_back(make_pair(edge[i].v,edge[i].w)); 52 G[edge[i].v].push_back(make_pair(edge[i].u,edge[i].w)); 53 } 54 if(num==n-1) break; 55 } 56 printf("%I64d ",sum); 57 } 58 59 60 int dfs(int u, int fa) 61 { 62 int cnt = 0; 63 for(int i=0;i<G[u].size();i++) 64 { 65 int v = G[u][i].first; 66 int w = G[u][i].second; 67 if(v==fa) continue; 68 int now = dfs(v, u); 69 cnt += now; 70 tot += 1.0 * now * (n - now) * w; 71 } 72 return cnt+1; 73 } 74 75 int main() 76 { 77 //freopen("in.txt","r",stdin); 78 int T; 79 scanf("%d",&T); 80 while(T--) 81 { 82 scanf("%d%d",&n,&m); 83 for(int i=0;i<=n;i++) {p[i]=i;G[i].clear();} 84 for(int i=0;i<m;i++) 85 { 86 scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); 87 } 88 Kruskal(); 89 tot=0; 90 dfs(1,-1); 91 printf("%.2f ",tot*2.0/(1.0*n)/(n-1.0)); 92 } 93 return 0; 94 }