hdu 4118 (树形DP||求树的重心)
来源:互联网 发布:随身带着淘宝到异界 编辑:程序博客网 时间:2024/06/07 10:31
题意:一棵n节点的树,每个节点有一个人,每个人离开自己的位置到另一个位置,每个位置只能有一个人,问这n个人移动距离和的最大值。
思路:11年成都区赛的题目,刚开始想着是匹配问题,但是求出任意两点的距离是不行的,后来想到如果找出树的重心就可以把树分成左右两部分,左边的点跟右边的点交换位置,两点交换位置的距离=两点到根节点的距离之和的2倍,总距离就是所有点到根节点距离之和的2倍了,当时犹豫了一下,如果节点数是奇数的话,这样是不是根节点没换位置呢?后来一想,这种交换位置每个点走的路径都经过根节点,根节点跟任意一个点交换一下就可以了,答案还是一样的。由于没考虑超int的问题wrong了,后来又想到用树形DP可以做,就改了算法。
树形DP:我们可以统计没条边被走了多少次,一条边可以把点分为左右两部分,两部分中点数较少的一部分都要离开自己的位置去另一边,这条边被走了min(son[u](右边点数),son[v])*2次,点数多的一部分有的位置是没变的,但是我们这样把每条边都操作一遍后,所有点的位置都变了。
两种方法的原理都是一样的,都是将树重心左边的点跟右边的点交换,树形DP不用求树的重心。
树形DP:
#pragma comment(linker, "/STACK:1024000000,1024000000")#include<stdio.h>#include<string.h>const int N=100100;int head[N],num,dis[N],son[N],f[N],size,root;__int64 ans;struct edge{int ed,w,next;}e[N*2];void addedge(int x,int y,int w){e[num].ed=y;e[num].w=w;e[num].next=head[x];head[x]=num++;e[num].ed=x;e[num].w=w;e[num].next=head[y];head[y]=num++;}int min(int a,int b){if(a<b)return a;return b;}void dfs(int u,int fa){int i,v;son[u]=1;for(i=head[u];i!=-1;i=e[i].next){v=e[i].ed;if(v==fa)continue;dfs(v,u);son[u]+=son[v];__int64 minson=min(son[v],size-son[v]);//边将点分为两部分,求最少的一部分ans+=e[i].w*minson*2;}}int main(){int i,n,t,op=1,x,y,w,sum;scanf("%d",&t);while(t--){memset(head,-1,sizeof(head));sum=0;num=0;scanf("%d",&n);for(i=1;i<n;i++){scanf("%d%d%d",&x,&y,&w);addedge(x,y,w);}ans=0;size=n;dfs(1,0);printf("Case #%d: %I64d\n",op++,ans);}return 0;}
找树的重心然后求点到根节点的距离:
#pragma comment(linker, "/STACK:1024000000,1024000000")#include<stdio.h>#include<string.h>const int N=100100;int head[N],num,son[N],f[N],size,root;__int64 dis[N],ans;struct edge{int ed,w,next;}e[N*2];void addedge(int x,int y,int w){e[num].ed=y;e[num].w=w;e[num].next=head[x];head[x]=num++;e[num].ed=x;e[num].w=w;e[num].next=head[y];head[y]=num++;}int max(int a,int b){if(a>b)return a;return b;}void getroot(int u,int father)//求树的重心 { int i,v; f[u]=0;son[u]=1; for(i=head[u];i!=-1;i=e[i].next) { v=e[i].ed; if(v==father)continue; getroot(v,u); son[u]+=son[v]; f[u]=max(f[u],son[v]); } f[u]=max(f[u],size-son[u]); if(f[u]<f[root])root=u; } void dfs(int u,int fa){int i,v;for(i=head[u];i!=-1;i=e[i].next){v=e[i].ed;if(v==fa)continue;dis[v]=dis[u]+e[i].w;dfs(v,u);}ans+=dis[u];}int main(){int i,n,t,op=1,x,y,w;scanf("%d",&t);while(t--){memset(head,-1,sizeof(head));ans=0;num=0;scanf("%d",&n);for(i=1;i<n;i++){scanf("%d%d%d",&x,&y,&w);addedge(x,y,w);}root=0;f[root]=size=n;getroot(1,0);dis[root]=0;dfs(root,0);//树的重心为根节点printf("Case #%d: %I64d\n",op++,ans*2);}return 0;}
- hdu 4118 (树形DP||求树的重心)
- 树形dp求树的重心 poj1655
- 树形DP求树的重心 --SGU 134
- POJ 1655 Balancing Act(求树的重心--树形DP)
- poj 1655 Balancing Act 【树形DP 求树的重心】
- SGU134 Centroid 树形DP基础题,求树的重心
- 求树的重心 POJ 1655、POJ 3107 树形DP
- poj1655Balancing Act 树的重心,树形dp
- 树的重心 树形DP SGU 134
- 树的重心——树形dp
- God Father (树形dp 树的重心)
- POJ3107-树的重心&树形DP-Godfather
- 树的重心(树形DP)
- Godfather (树形dp,树的重心)
- Godfather (树形dp + 树的重心)
- poj 3107 Godfather 求树的所有重心 树形DP基础题
- Balancing Act (树形dp 求树的重心板题)
- [codevs 3639] 树的中心---树形DP(树的重心)
- tcgetattr() failed这个错误问题
- 使用apache htpasswd命令
- 堆的数组实现
- 动手写一个用户注册协议倒计时
- ios横竖屏解决方案
- hdu 4118 (树形DP||求树的重心)
- 利用QrCode.Net生成二维码 asp.net mvc c#
- typedef struct 在C和C++中用法的区别
- apt-get update errors
- main函数执行之前的相关内容
- [C] 回调函数
- 线程同步
- [C] 可变参数
- linux内核奇遇记之md源代码解读之六