1737 配对

 

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
 收藏
 关注
给出一棵n个点的树,将这n个点两两配对,求所有可行的方案中配对两点间的距离的总和最大为多少。
Input
一个数n(1<=n<=100,000,n保证为偶数)
接下来n-1行每行三个数x,y,z表示有一条长度为z的边连接x和y(0<=z<=1,000,000,000)
Output
一个数表示答案
Input示例
6
1 2 1
1 3 1
1 4 1
3 5 1
4 6 1
Output示例
7
//配对方案为(1,2)(3,4)(5,6)
﹡    LH (题目提供者)
 
 
考虑每一条边被统计进答案几次。
若断开这条边后树形成大小为s1、s2的两个联通块则这条边最多被统计min(s1,s2)次。
构造方案的做法为:找出树的重心,让所有n/2条路径都经过重心即可(只要保证删去重心后任意同一联通块中的两点不构成路径即可,因为是重心,所以这是很好构造的)
这样构造出来的配对方案满足了每条边都没被统计min(s1,s2)次,所以这道题只要求出断开每条边后两个联通块的大小即可。
时间复杂度O(n)
 
 1 #include <cstdio>
 2 #include <cctype>
 3 #include <vector>
 4 
 5 typedef long long LL;
 6 const int MAXN=100010;
 7 
 8 int n;
 9 
10 LL ans;
11 
12 int son[MAXN];
13 
14 struct node {
15     int to,val;
16     node() {}
17     node(int to,int val):to(to),val(val) {}
18 };
19 
20 std::vector<node> Graph[MAXN];
21 
22 inline void read(int&x) {
23     int f=1;register char c=getchar();
24     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
25     for(;isdigit(c);x=x*10+c-48,c=getchar());
26     x=x*f;
27 }
28 
29 void DFS(int now,int fa) {
30     son[now]=1;
31     for(register int i=0;i<Graph[now].size();++i) {
32         node p=Graph[now][i];
33         if(p.to==fa) continue;
34         DFS(p.to,now);
35         son[now]+=son[p.to];
36     }
37     return;
38 }
39 
40 void DFS_Ans(int now,int fa) {
41     for(register int i=0;i<Graph[now].size();++i) {
42         node p=Graph[now][i];
43         if(p.to==fa) continue;
44         DFS_Ans(p.to,now);
45         ans+=(LL)(son[p.to]<n-son[p.to]?son[p.to]:(n-son[p.to]))*p.val;
46     }
47     return;
48 }
49 
50 int hh() {
51     read(n);
52     for(register int x,y,z,i=1;i<n;++i) {
53         read(x);read(y);read(z);
54         Graph[y].push_back(node(x,z));
55         Graph[x].push_back(node(y,z));
56     }
57     DFS(1,0);
58     DFS_Ans(1,0);
59     printf("%lld
",ans);
60     return 0;
61 }
62 
63 int sb=hh();
64 int main(int argc,char**argv) {;}
代码
原文地址:https://www.cnblogs.com/whistle13326/p/7593529.html