http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1737
题意:
思路:
树的重心。
树的重心就是其所以子树的最大的子树结点数最少,删除这个点后最大连通块的结点数最小,也就说各个连通块尽量平衡。
这道题的话就是先求一个重心,然后求各个点到重心的距离之和。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<queue> 7 #include<cmath> 8 #include<map> 9 using namespace std; 10 11 const int maxn=1e5+5; 12 const int INF=0x3f3f3f3f; 13 14 int n; 15 16 vector<pair<int,int> > edge[maxn]; 17 18 int zx,sz; 19 int son[maxn],vis[maxn]; 20 long long ww[maxn]; //各个点到重心的距离 21 22 void init() 23 { 24 for(int i=1;i<=n;i++) 25 edge[i].clear(); 26 memset(vis,0,sizeof(vis)); 27 memset(ww,0,sizeof(ww)); 28 sz=INF; 29 zx=-1; 30 } 31 32 void dfs(int u) 33 { 34 vis[u]=1; 35 son[u]=0; 36 int temp=0; 37 for(int i=0;i<edge[u].size();i++) 38 { 39 int v=edge[u][i].first; 40 if(!vis[v]) 41 { 42 dfs(v); 43 son[u]+=son[v]+1; //找到该子树中的最大结点数 44 temp=max(temp,son[v]+1); 45 } 46 } 47 temp=max(temp,n-son[u]-1); //删去重心后子树最大结点数和非重心的子树比较 48 if(temp<sz) 49 { 50 zx=u; 51 sz=temp; 52 } 53 } 54 55 void sum(int u) 56 { 57 vis[u]=1; 58 for(int i=0;i<edge[u].size();i++) 59 { 60 int v=edge[u][i].first; 61 if(!vis[v]) 62 { 63 ww[v] =ww[u]+edge[u][i].second; 64 sum(v); 65 } 66 } 67 } 68 69 int main() 70 { 71 //freopen("D:\\input.txt","r",stdin); 72 while(~scanf("%d",&n)) 73 { 74 init(); 75 int u,v,w; 76 for(int i=1;i<=n-1;i++) 77 { 78 scanf("%d%d%d",&u,&v,&w); 79 edge[u].push_back(make_pair(v,w)); 80 edge[v].push_back(make_pair(u,w)); 81 } 82 83 dfs(1); 84 memset(vis,0,sizeof(vis)); 85 sum(zx); 86 long long ans=0; 87 for(int i=1;i<=n;i++) 88 ans+=ww[i]; 89 printf("%lld\n",ans); 90 } 91 }
时间: 2024-10-08 10:17:44