HDU 2196 Computer (树上最长路)【树形DP】

<题目链接>

题目大意:

输出树上每个点到其它点的最大距离。

解题分析:

下面的做法是将树看成有向图的做法,计算最长路需要考虑几种情况。

dp[i][0] : 表示以i为根的子树中的结点与i的最大距离

dp[i][1] : 表示以i为根的子树中的结点与u的次大距离

dp[i][2] : 表示i往父亲节点方向走的最大距离

第一就是点 i 在以点 i 为根的子树中的最长距离,这个可以直接在点 i 的子树中求得;

第二就是点 i 朝父亲节点方向的最长距离,这个距离分为三种: 

1) 点 i 在以 fa 为根的子树中的最长路径上,这时的它朝fa 的最长距离(但是不超过fa的子树继续向上,即只在fa的子树的其它分支进行操作)为 cost<u,fa> + 以fa 为根的子树中的次长路;                              

2)点 i 不在以fa 为根的子树的最长路径上,这时它朝 fa 的最长距离为(但是不超过fa 的子树继续向上,即只在fa的子树的其它分支进行操作), cost<u,fa> + fa 子树中的最长路;

3)点 i 向 fa 的 fa 的子树进行扩展比较,所以需要和dp[fa][2] 比较。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N = 1e4 +10;
 7 int dp[N][5];
 8 struct Node{
 9     int to,next,cost;
10 }edge[N];
11 
12 int n,cnt,head[N];
13 void init(){
14     cnt=0;
15     memset(head,-1,sizeof(head));
16 }
17 void addedge(int u,int v,int w){
18     edge[cnt].to=v,edge[cnt].cost=w,edge[cnt].next=head[u];
19     head[u]=cnt++;
20 }
21 void dfs1(int u){
22     int ans1=0,ans2=0;
23     for(int i=head[u];~i;i=edge[i].next){
24         int v=edge[i].to,cost=edge[i].cost;
25         dfs1(v);
26         int res=dp[v][0]+cost;
27         if(res>=ans1){   
28             ans2=ans1;      //ans1记录最长路,ans2记录次长路
29             ans1=res; 
30         }else if(res>ans2) ans2=res;
31     }
32     dp[u][0]=ans1;        //dp[u][0]为以u为根的子树的最长路
33     dp[u][1]=ans2;        //dp[u][1]为以u为根的子树的次长路
34 }
35 void dfs2(int fa){
36     for(int i=head[fa];~i;i=edge[i].next){
37         int v=edge[i].to,cost=edge[i].cost;
38         dp[v][2]=max(dp[fa][2],dp[v][0]+cost == dp[fa][0]? dp[fa][1]:dp[fa][0])+cost; 
39         //dp[fa][2]表示向父亲方向走的最长路;  按v是否在以fa为根的子树中的最长路径上分类讨论,dp[v][2]有两种选择
40         //相当于,上面的式子考虑了v向fa方向走最长路的三种情况
41         dfs2(v);
42     }
43 }
44 int main(){
45     while(~scanf("%d",&n)){
46         init();
47         for(int i=2;i<=n;i++){
48             int u,w;scanf("%d%d",&u,&w);
49             addedge(u,i,w);
50         }
51         dfs1(1);dfs2(1);
52         for(int i=1;i<=n;i++){
53             printf("%d\n",max(dp[i][0],dp[i][2]));    //以i为根的最长路;向父亲方向走的最长路
54         }
55     }
56 }

2019-02-03

猜你喜欢

转载自www.cnblogs.com/00isok/p/10349885.html