Hdu2196-Computer (树形dp)(经典题)

传送门:Computer

题意:有 n 个点,通过 n-1 条边连成一棵树,每条边有一个权值,求从每个点出发的简单路径的最大长度。

思路:树形dp

首先以 1 为根建树,这样每个点能走的最大路径有两种情况:往下沿着子节点走或往上沿着父结点走。假设根节点为 rt,我们定义:

dp[rt][0] 表示以 rt 为根的子树上的节点到 rt 的最长距离。

dp[rt][1] 表示以 rt 为根的子树上的节点到 rt 的次长距离。

dp[rt][2] 表示从 rt 往上走能走的最长距离。

我们先通过一次 dfs 求出 dp[rt][0] 与 dp[rt][1]。此时只需要简单的 dfs 和更新就可以了。

然后我们通过第二次 dfs 求出 dp[rt][2]。我们假设 to 是 rt 的一个子节点,此时我们需要分两种情况考虑:

dp[rt][0] 经过了节点 to,那么从 to 往上走的最长的路可能是【连接 rt 和 to 的边】加上(【rt 往上走的最长的路】或【rt 往下走的次长的路】)。

dp[rt][0] 没有经过节点 to,那么从 to 往上走的最长的路可能是【连接 rt 和 to 的边】加上(【rt 往上走的最长的路】或【rt 往下走的最长的路】)。

即:

dp[to][2]=e[i].w+max(dp[rt][2],dp[rt][1])(dp[rt][0] 经过节点 to)

dp[to][2]=e[i].w+max(dp[rt][2],dp[rt][0])(dp[rt][0] 没有经过节点 to)

这样我们求出了一个点【往上走的最大距离】和【往下走的最大距离】,最后我们只需要在这两者中选出一个较大的作为答案即可。

 

AC代码:

#include 
#include 
#include 
using namespace std;
const int maxn=1e4+7;
struct node{
    int to,nxt,w;
}e[maxn*2];
int tot,head[maxn],dp[maxn][3],mx[maxn];
void add(int u,int v,int w){
    e[tot].nxt=head[u];
    e[tot].to=v;
    e[tot].w=w;
    head[u]=tot++;
    return;
}
void add_edge(int u,int v,int w){
    add(u,v,w);
    add(v,u,w);
    return;
}
void dfs1(int rt,int p){
    for(int i=head[rt];~i;i=e[i].nxt){
        int to=e[i].to;
        if(to==p) continue;
        dfs1(to,rt);
        if(dp[to][0]+e[i].w>dp[rt][0]){
            mx[rt]=to;
            dp[rt][1]=dp[rt][0];
            dp[rt][0]=dp[to][0]+e[i].w;
        }else if(dp[to][0]+e[i].w>dp[rt][1]){
            dp[rt][1]=dp[to][0]+e[i].w;
        }
    }
    return;
}
void dfs2(int rt,int p){
    for(int i=head[rt];~i;i=e[i].nxt){
        int to=e[i].to;
        if(to==p) continue;
        if(to==mx[rt]) dp[to][2]=e[i].w+max(dp[rt][2],dp[rt][1]);
        else dp[to][2]=e[i].w+max(dp[rt][2],dp[rt][0]);
        dfs2(to,rt);
    }
    return;
}
int main(void){
    int n;while(~scanf("%d",&n)){
        tot=0;
        for(int i=1;i<=n;i++){
            head[i]=-1;
            dp[i][0]=dp[i][1]=dp[i][2]=0;
        }
        for(int u=2;u<=n;u++){
            int v,w;scanf("%d%d",&v,&w);
            add_edge(u,v,w);
        }
        dfs1(1,0);
        dfs2(1,0);
        for(int i=1;i<=n;i++){
            printf("%d\n",max(dp[i][0],dp[i][2]));
        }
    }
    return 0;
}

 

你可能感兴趣的:(动态规划-树形DP)