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 <cstdio>
#include <cstring>
#include <algorithm>
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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章