zoukankan      html  css  js  c++  java
  • hdu 2196【树形dp】

    http://acm.hdu.edu.cn/showproblem.php?pid=2196

    题意:找出树中每个节点到其它点的最远距离。

    题解:

      首先这是一棵树,对于节点v来说,它到达其它点的最远距离可以走两个方向,一个是向它的子节点走,不妨称作正向走;一个是向它的父节点方向,不妨称作反向走。也就是说节点v能到达的最远距离是max{正向走的最远距离,反向走的最远距离}。所以可以先dfs一次求出每个节点能正向走的最大距离。显然反向走一定会经过父节点,这时就会出现两种情况:1.父节点u正向走的最远距离经过子节点v。2.父节点u走的最远距离不经过子节点v。当经过子节点v时,显然要算v反向走的最远距离时不能走u的正向最远的那条经过自己的路径,而u的正向第二远的路径将是最优的选择。可以想想看,v反向最远当然是由u的正向最远转移过来的,这个正向最远经不经过v很关键。因此正向dfs时还要记录一个第二最远的距离。

      设dp[][3],dp[v][0]表示v正向走的最远距离,dp[v][1]表示v正向走的第二最远距离,dp[v][2]表示v反向走的最远距离。

      那么答案显然是:ans=max{dp[v][0],dp[v][2]}。

      其中:当u最远不经过v时:dp[v][2]=max{dp[u][2],dp[u][0]}+cost;

        当u最远经过v时:dp[v][2]=max{dp[u][2],dp[u][1]}+cost;

      我之前有个非常疑惑的地方就是为什么dp[v][2]的转移还要有dp[u][2]?我直接根据u经不经过v分两种情况不就是dp[v][2]了吗,怎么还要跟dp[u][2]+cost之间取个最大值?后来想想才明白,其实这也是个状态转移啊!dp[u][2]表示u反向走的最远距离,而dp[u][0],dp[u][1]都是正向走的距离,当由u推v的时候当然要从u的正向和反向之间取个最大值了!

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<vector>
     5 #include<algorithm>
     6 using namespace std;
     7 const int MAXN=10007;
     8 struct Node{
     9     int to,cost;
    10 };
    11 vector<Node> tree[MAXN];
    12 int dp[MAXN][3];
    13 int N;
    14 
    15 void init()
    16 {
    17     memset(dp,0,sizeof(dp));
    18     for(int i=0;i<=N;i++)
    19         tree[i].clear();
    20 }
    21 
    22 void dfs1(int u,int fa)
    23 {
    24     int FirstMax=0,SecondMax=0;
    25     for(int i=0;i<tree[u].size();i++){
    26         int v=tree[u][i].to;
    27         int c=tree[u][i].cost;
    28         if(v==fa) continue;
    29         dfs1(v,u);
    30         if(dp[v][0]+c>FirstMax){
    31             SecondMax=FirstMax;
    32             FirstMax=dp[v][0]+c;
    33         }else if(dp[v][0]+c>SecondMax)
    34             SecondMax=dp[v][0]+c;
    35     }
    36     dp[u][0]=FirstMax;
    37     dp[u][1]=SecondMax;
    38 }
    39 
    40 void dfs2(int u,int fa)
    41 {
    42     int t;
    43     for(int i=0;i<tree[u].size();i++){
    44         int v=tree[u][i].to;
    45         int c=tree[u][i].cost;
    46         if(v==fa) continue;
    47         if(dp[u][0]==dp[v][0]+c)
    48             t=dp[u][1];
    49         else t=dp[u][0];
    50         dp[v][2]=max(dp[u][2],t)+c;
    51         dfs2(v,u);
    52     }
    53 }
    54 
    55 int main()
    56 {
    57     while(scanf("%d",&N)==1)
    58     {
    59         init();
    60         int a,b;
    61         Node n1;
    62         for(int i=2;i<=N;i++){
    63             scanf("%d%d",&a,&b);
    64             n1.to=a,n1.cost=b;
    65             tree[i].push_back(n1);
    66             n1.to=i;
    67             tree[a].push_back(n1);
    68         }
    69         dfs1(1,1);
    70         dfs2(1,1);
    71         for(int i=1;i<=N;i++)
    72             printf("%d
    ",max(dp[i][0],dp[i][2]));
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    Gitblit版本服务器环境部署记录
    LVS+Keepalived 高可用环境部署记录(主主和主从模式)
    LVM常规操作记录梳理 [扩容、缩容、快照等]
    MFS+Keepalived双机高可用热备方案操作记录
    Docker容器时间跟主机时间保持同步的操作记录
    搜狗拼音输入法LINUX版安装
    Android实现透明的颜色效果(zz)
    android.database.CursorIndexOutOfBoundsException:Index -1 requested, with a size of 1(zz)
    View 的setTag() 和 getTag()
    android 布局的两个属性 dither 和 tileMode
  • 原文地址:https://www.cnblogs.com/zxhyxiao/p/7653005.html
Copyright © 2011-2022 走看看