1、【HDU 5723】Abandoned country(最小生成树+树形dp)
题意:n(n≤100000)个城市,m(m≤1000000)条路,要修建(n-1)条路使这n个城市连通,题目中告诉我们修建每条路的费用,需要求两个问题:1、修建(n-1)条路的最小费用 2、路修建好了之后,任意两点之间的长度的期望
解题思路:
修建(n-1)条路的最小费用==>最小生成树
路修建好了之后,任意两点之间的长度的期望:实际上就是求任意两点之间的平均距离。对于边X,求所有可能的路径经过此边的次数:设这条边两端的点数分别为A和B, 点A的子树的大小是size(A),设点B的子树大小是size(B),【这里所说的子树都是不经过边X的】那么这条边被经过的次数就是size(A)*size(B),它对总的距离和的贡献就是
(size(A)*size(B)*边X的长度)。求出所有边的贡献总和然后除以(n*(n-1)/2)就是所求值
long long没有处理好,wa了很多次。
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <string> 6 #include <vector> 7 using namespace std; 8 #define ll long long 9 const int N=1e6+10; 10 11 struct node{ 12 int u, v, w; 13 friend bool operator < (const node n1, const node n2){ 14 return n1.w<n2.w; 15 } 16 }a[2*N]; 17 18 struct Node{ 19 int v, len; 20 Node(int _v, int _len):v(_v), len(_len){} 21 }; 22 23 int fa[N]; 24 vector<Node>vec[N]; 25 int find(int x) 26 { 27 return fa[x]=(fa[x]==x?x:find(fa[x])); 28 } 29 ll kruskal(int n, int m) 30 { 31 ll ans=0; 32 int tmp=0; 33 for(int i=1; i<=n; i++) fa[i]=i, vec[i].clear(); 34 for(int i=0; i<m; i++) 35 { 36 if(tmp>=n-1) break; 37 int ui=find(a[i].u), vi=find(a[i].v); 38 if(ui!=vi) 39 { 40 tmp++, fa[vi]=ui, ans+=(ll)a[i].w; 41 vec[a[i].u].push_back(Node(a[i].v, a[i].w)); 42 vec[a[i].v].push_back(Node(a[i].u, a[i].w)); 43 } 44 } 45 return ans; 46 } 47 48 ll dis[N]; 49 int sum[N]; 50 int n; 51 void dfs(int u, int p){ 52 53 sum[u]=1; 54 for(int i=0; i<(int)vec[u].size(); i++){ 55 int vi = vec[u][i].v; 56 int wi = vec[u][i].len; 57 if(vi==p) continue; 58 dfs(vi, u); 59 sum[u]+=sum[vi]; 60 dis[u] += dis[vi]+((ll)sum[vi]*(n-sum[vi]))*wi; 61 } 62 63 } 64 65 int main(){ 66 int t; 67 scanf("%d", &t); 68 while(t--){ 69 int m, lena=0; 70 scanf("%d%d", &n, &m); 71 int ui, vi, wi; 72 for(int i=0; i<m; i++){ 73 scanf("%d%d%d", &ui, &vi, &wi); 74 a[lena].u=ui, a[lena].v=vi, a[lena].w=wi, lena++; 75 a[lena].u=vi, a[lena].v=ui, a[lena].w=wi, lena++; 76 } 77 sort(a, a+lena); 78 ll ans = kruskal(n, lena); 79 memset(dis, 0, sizeof(dis)); 80 dfs(1, -1); 81 ll s = (ll)n*(n-1)/2; 82 printf("%lld %.2lf\n", ans, dis[1]*1.0/s); 83 } 84 return 0; 85 }
时间: 2025-01-04 03:34:58