HDU 2196 Computer(树形 dp)

来源:互联网 发布:淘宝自主品牌怎么回事 编辑:程序博客网 时间:2024/05/22 03:07

Computer

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 31198    Accepted Submission(s): 3987


Problem Description
A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information. 


Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.
 

Input
Input file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.
 

Output
For each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).
 

Sample Input
51 12 13 11 1
 

Sample Output
32344
题意:学校里一开始只有一台编号为1 的电脑 ,接下来学校里 购进 n-1台,对于第i台 将他连到第 v 台上。需要的线长度 为 w 问你每一台 能到达的最远距离。
思路: 树形dp的经典题。。对于每一个节点 他能到达的最远距离 就只有两种情况 第一是 以他为父节点能到达叶节点的最远距离。第二是 通过他的父亲向上走,再走到他父亲不经过这个点的最远叶子节点。
在这里 dp[i][0] 表示 以 i 为父节点 能到达的 叶子节点的最远距离。
dp[i][1] 表示以i为父节点能到达的叶子节点的次远距离。当然如果i 为父节点
最远距离经过j节点 那么次远距离肯定不经过 j 节点。
dp[i][2]表示通过i的父节点能走的最远距离。
两边dfs 第一遍跑出 最远距离和次远距离和记录每一个节点的最远距离经过他的哪个儿子(longest记录)
第二遍dfs 跑出 dp[i][2] 对于一个节点 j 如果他的父亲节点的最远叶节点经过j 那么 dp[j][2] 取决于 父亲节点的次远距离和父亲节点通过他的父亲节点能到达的最远距离 哪个比较大。
如果他的父亲节点的最远叶节点不经过j 那么 dp[j][2] 取决于 父亲节点的最远距离和父亲节点通过他的父亲节点能到达的最远距离 哪个比较大。
注意 思想 第一遍dfs 是从 叶节点向父节点更新, 第二遍dfs 是从父节点向叶节点更新。
代码:
#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#define M 10005#define N 10005using namespace std;struct node{int u,v,next,w;}edge[M*2];int head[N],longest[N];int dp[N][3];int n,cnt;void add(int u,int v,int w){edge[++cnt].u=u;edge[cnt].v=v;edge[cnt].w=w;edge[cnt].next=head[u];head[u]=cnt;return ;}int dfs1(int u,int fa){if(dp[u][0]>0) return dp[u][0];dp[u][0]=dp[u][1]=0;for(int k=head[u];k!=-1;k=edge[k].next){int v,w;v=edge[k].v;   w=edge[k].w;if(v==fa) continue;if(dp[u][0]<dfs1(v,u)+w){longest[u]=v;dp[u][1]=max(dp[u][1],dp[u][0]);dp[u][0]=dfs1(v,u)+w;}else if(dp[u][1]<dfs1(v,u)+w)//注意if  else if  的语句逻辑  只执行其中的一个语句。 { dp[u][1]=max(dp[u][1],dfs1(v,u)+w);}}return dp[u][0];}void dfs2(int u,int fa){for(int k=head[u];k!=-1;k=edge[k].next){int v=edge[k].v;int w=edge[k].w;if(v==fa) continue;if(longest[u]==v) dp[v][2]=w+max(dp[u][1],dp[u][2]);else dp[v][2]=w+max(dp[u][0],dp[u][2]);dfs2(v,u);}return ;}int main(){int v,w;while(scanf("%d",&n)!=EOF){if(n==0) break;memset(head,-1,sizeof(head));memset(dp,-1,sizeof(dp));memset(longest,0,sizeof(longest));cnt=0;for(int i=2;i<=n;i++){scanf("%d %d",&v,&w);add(i,v,w);add(v,i,w);}dfs1(1,-1);//dp[1][2]=dp[1][0];在这里不能进行这一步 ,,因为 我们将1 看做根结点。  就拿样例来讲  如果这里dp[1][2] 为  3 的话  //那么对于处理 1的子节点 2时 就会 出现很明显的错误。 dfs2(1,-1);//for(int i=1;i<=n;i++) printf("%d %d\n",dp[i][0],dp[i][2]);for(int i=1;i<=n;i++ ) printf("%d\n",max(dp[i][0],dp[i][2]));}return 0;}