http://acm.hdu.edu.cn/showproblem.php?pid=4118
2 4 1 2 3 2 3 2 4 3 2 6 1 2 3 2 3 4 2 4 1 4 5 8 5 6 5
Case #1: 18 Case #2: 62
/** hdu 4118 树形dp 题目大意:一棵n节点的树,每个节点有一个人,每个人离开自己的位置到另一个位置,每个位置只能有一个人,问这n个人移动距离和的最大值。 解题思路:(转)如果找出树的重心就可以把树分成左右两部分,左边的点跟右边的点交换位置,两点交换位置的距离=两点到根节点的距离之和的2倍, 总距离就是所有点到根节点距离之和的2倍了,当时犹豫了一下,如果节点数是奇数的话,这样是不是根节点没换位置呢?后来一想, 这种交换位置每个点走的路径都经过根节点,根节点跟任意一个点交换一下就可以了,答案还是一样的。 树形DP:我们可以统计没条边被走了多少次,一条边可以把点分为左右两部分,两部分中点数较少的一部分都要离开自己的位置去另一边, 这条边被走了min(son[u](右边点数),son[v])*2次,点数多的一部分有的位置是没变的,但是我们这样把每条边都操作一遍后,所有点的位置都变了。 注:递归dfs会爆内存。 */ #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; typedef long long LL; const int maxn=100005; struct note { int v,w,next; } edge[maxn*2]; int head[maxn],ip; int n,vis[maxn],num[maxn],sta[maxn]; LL ans; void init() { memset(head,-1,sizeof(head)); ip=0; } void addedge(int u,int v,int w) { edge[ip].v=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++; } ///递归形式会超出内存 void dfs(int u,int pre) { for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(v==pre)continue; dfs(v,u); num[u]+=num[v]; ans+=(LL)edge[i].w*2*min(num[v],n-num[v]); } num[u]++; } ///用栈实现非递归形式 void dfs1(int u) { memset(vis,0,sizeof(vis)); int top=0; sta[top++]=u; vis[u]=1; while(top>0) { bool flag=1; int t=sta[top-1]; for(int i=head[t]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(vis[v])continue; sta[top++]=v; vis[v]=1; flag=0; } if(flag==0)continue; for(int i=head[t]; i!=-1; i=edge[i].next) { int v=edge[i].v; if(num[v]!=0) { num[t]+=num[v]; ans+=(LL)edge[i].w*2*min(num[v],n-num[v]); } } num[t]++; top--; } } int main() { int T,tt=0; scanf("%d",&T); while(T--) { scanf("%d",&n); init(); for(int i=1; i<n; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); addedge(v,u,w); } ans=0; memset(num,0,sizeof(num)); ///dfs1(1); dfs(1,-1); printf("Case #%d: %I64d\n",++tt,ans); } return 0; }
原文:http://blog.csdn.net/lvshubao1314/article/details/43802843