HDU 2196 Computer 树形DP 经典题

给出一棵树,边有权值,求出离每一个节点最远的点的距离

 

树形DP,经典题

本来这道题是无根树,可以随意选择root,

但是根据输入数据的方式,选择root=1明显可以方便很多。

我们先把边权转化为点权,放在数组cost中

令tree(i)表示以节点i为根的子树

对于节点i,离该节点最远的点要不就是在tree(i)中,要不就是在father(i)上面

令:

dp[i][1] : 在子树tree(i)中,离i最远的距离

dp[i][2] : 在子树tree(i)中,离i第二远的距离 (递推的时候需要)

dp[i][0] : 在树tree(root)-tree(i)中,离i最远的距离

son[i] : 在子树tree(i)中,离i最远的点是在tree(son[i])中,即最远路径经过节点son[i]

 

则对于每一个i,离i最远的距离=max(dp[i][0],dp[i][1])

 

流程:

0.链式前向星建树

1.dfs1,确定dp[i][1]

2.dfs2,确定dp[i][2]

dfs1和dfs2都很简单

3.dfs3,递推确定dp[i][0]

 

 

  1 #include<cstdio>
  2 #include<cstring>
  3 
  4 using namespace std;
  5 
  6 const int maxn=10000+5;
  7 const int inf=0x3f3f3f3f;
  8 
  9 inline int max(int a,int b)
 10 {
 11     return a>b?a:b;
 12 }
 13 
 14 struct Edge
 15 {
 16     int to,next;
 17 };
 18 Edge edge[maxn];
 19 int head[maxn];
 20 int tot;
 21 int cost[maxn];
 22 int son[maxn];
 23 int dp[maxn][3];
 24 
 25 void init()
 26 {
 27     memset(head,-1,sizeof head);
 28     tot=0;
 29     memset(dp,0,sizeof dp);
 30     memset(son,-1,sizeof son);
 31 }
 32 
 33 void addedge(int u,int v)
 34 {
 35     edge[tot].to=v;
 36     edge[tot].next=head[u];
 37     head[u]=tot++;
 38 }
 39 
 40 void solve(int n);
 41 void dfs1(int u,int pre);
 42 void dfs2(int u,int pre);
 43 void dfs3(int u,int pre);
 44 
 45 int main()
 46 {
 47     int n;
 48     while(~scanf("%d",&n))
 49     {
 50         init();
 51         cost[1]=0;
 52         for(int i=2;i<=n;i++)
 53         {
 54             int u;
 55             scanf("%d %d",&u,&cost[i]);
 56             addedge(u,i);
 57         }
 58         solve(n);
 59     }
 60     return 0;
 61 }
 62 
 63 void solve(int n)
 64 {
 65     dfs1(1,-1);
 66     dfs2(1,-1);
 67     dp[1][0]=0;
 68     dfs3(1,-1);
 69 
 70     for(int i=1;i<=n;i++)
 71     {
 72         printf("%d\n",max(dp[i][0],dp[i][1]));
 73     }
 74     return ;
 75 }
 76 
 77 void dfs1(int u,int pre)
 78 {
 79     for(int i=head[u];~i;i=edge[i].next)
 80     {
 81         int v=edge[i].to;
 82         dfs1(v,u);
 83         if(dp[v][1]+cost[v]>dp[u][1])
 84         {
 85             dp[u][1]=dp[v][1]+cost[v];
 86             son[u]=v;
 87         }
 88     }
 89 }
 90 
 91 void dfs2(int u,int pre)
 92 {
 93     for(int i=head[u];~i;i=edge[i].next)
 94     {
 95         int v=edge[i].to;
 96         dfs2(v,u);
 97         if(v==son[u])
 98             continue;
 99         if(dp[v][1]+cost[v]>dp[u][2])
100             dp[u][2]=dp[v][1]+cost[v];
101     }
102 }
103 
104 void dfs3(int u,int pre)
105 {
106     for(int i=head[u];~i;i=edge[i].next)
107     {
108         int v=edge[i].to;
109         if(v==son[u])
110         {
111             dp[v][0]=max(dp[u][0],dp[u][2])+cost[v];
112         }
113         else
114         {
115             dp[v][0]=max(dp[u][0],dp[u][1])+cost[v];
116         }
117         dfs3(v,u);
118     }
119 }
View Code

 

转载于:https://www.cnblogs.com/-maybe/p/4743949.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值