2012 Asia ChangChun Regional Contest - E. Conquer a New Region
算法提示
并查集
题目大意
有 n 个城镇,编号为 1 - n ,有 n - 1 条路将它们联通,任何两个城镇之间有唯一的一条路径,每条路有它们的各自的通行量,从一个城镇到另一个城镇的通行量路径上的最小的那个量(如1 2 2,2 3 1,则 1 到 3 的最大通行量为 1)。现在需要找一个中心城市,使这个城市到其他各个城市的通行量之和最大。
做法分析
令 sum[i] 表示 i 结点所在联通块中通行量之和的最大值,cnt[i] 表示 i 结点所在联通块中的结点数。
我们首先考虑在这棵树中,对于一条边权最小的边 ( u , v , d ),断开这条边可以得到 u 子树和 v 子树,那么所求答案为 max{ sum[u] + cnt[v] * d , sum[v] + cnt[u] * d },而式子中 sum[u] 和 sum[v] 又是重复子问题。
于是我们将边权从大到小排序,每次连接两棵子树,并算出新子树的最大值 sum,并维护新子树的结点数 cnt 。
参考代码
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 #define MAXN 200010 8 #define MAX(a,b) (a>b?a:b) 9 typedef long long LL; 10 11 int n,f[MAXN],cnt[MAXN]; 12 LL sum[MAXN]; 13 14 struct node 15 { 16 int u,v,d; 17 bool operator<(const node &x) const{ 18 return d>x.d; 19 } 20 }e[MAXN]; 21 22 void Init() 23 { 24 memset(f,0,sizeof(f)); 25 memset(sum,0,sizeof(sum)); 26 int i; 27 for(i=1;i<n;++i) 28 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].d); 29 for(i=1;i<=n;++i) cnt[i]=1; 30 sort(e+1,e+n); 31 } 32 33 int Find(int u) 34 { 35 return f[u]?f[u]=Find(f[u]):u; 36 } 37 38 void Work() 39 { 40 int i,fu,fv; 41 for(i=1;i<n;++i){ 42 fu=Find(e[i].u); fv=Find(e[i].v); 43 sum[fu]=MAX((1LL*cnt[fu]*e[i].d+sum[fv]),(1LL*cnt[fv]*e[i].d+sum[fu])); 44 f[fv]=fu; cnt[fu]+=cnt[fv]; 45 } 46 printf("%I64d\n",sum[fu]); 47 } 48 49 int main() 50 { 51 while(~scanf("%d",&n)){ 52 Init(); 53 Work(); 54 } 55 return 0; 56 }
题目链接
2012 Asia ChangChun Regional Contest - E. Conquer a New Region

浙公网安备 33010602011771号