HDU 4118 Holiday's Accommodation 贪心(树的重心)

来源:互联网 发布:贵州黔信数据有限公司 编辑:程序博客网 时间:2024/06/06 02:23

题意:给你n个点和n-1条边,每个边有边权,每个点是一个城市,每个边是一条路,每个城市只有一个人,每个城市的人都要和另外一个城市的人交换家来住,每一个人都要交换,不会有多个人要和同一个人 交换,问交换的时候,两个城市的人都要走相同的距离,当所有的人家都交换完毕的时候,总路程的最大值。


想法:开始看到这道题,最先想到的是暴力求树的直径,但是时间复杂度是O(n^2)超时,n<=100000,显然是不行的。后来就想不出来了,后来看了学长的资料,发现我们要求得就是每一条边被使用了几次,然后直接就可以算出综合了,后来又在网上查了一下,这就和树的重心由关系了。然后就看了一下,今天太晚了,那题就明天再写。

a---------b我提取一条边,我可以算出b的右边有多少个点,a的左边有多少个点,那么必然e(a,b)被用的次数时MIN(zuo_a,you_a)。这里还有一个要注意的点,就是说,我以一个任意点作为原点进行搜索,所以我不知道是从a往b搜还是反过来,所以要选择MIN_a,MIN_b中小的那一个。

#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int N=100000+5;int n,befno,skt[N];__int64 num[N];struct node{int u,v,next,w;}e[N*2];int head[N],cnt,vis[N];void Init(){memset(head,-1,sizeof(head));cnt=0;}void add(int a,int b,int c){e[cnt].u=a;e[cnt].v=b;e[cnt].w=c;e[cnt].next=head[a];head[a]=cnt++;} void Input(){scanf("%d",&n);for(int i=1;i<n;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);add(a,b,c);add(b,a,c); }}int MIN(int x,int y){if(x<y) return x;return y;}int dfs(int u,int fa){int aftno=0;for(int i=head[u];i+1;i=e[i].next){int v=e[i].v;if(fa==v) continue;aftno+=dfs(v,u);}skt[u]=aftno;return aftno+1;}void treatment(int ca){__int64 sum=0;memset(skt,0,sizeof(skt));int k=dfs(1,-1);for(int i=0;i<cnt;i+=2){int v=e[i].v;int u=e[i].u;if(skt[u]<skt[v]){swap(u,v);}sum+=2*e[i].w*MIN(skt[v]+1,n-skt[v]-1);}printf("Case #%d: %I64d\n",ca,sum);}int main(){int t,ca=1;scanf("%d",&t);while(t--){Init();Input();treatment(ca++);}return 0;} //DFS 方向不确定//一条边最多用几次//DFS 子孙个数 

1 0
原创粉丝点击