【校隊排位賽#7 J】 HDU 2196 Computer 樹形DP 詳解

Problem Description
A school bought the first computer some time ago(so this computer’s id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information.

Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.

Input
Input file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.

Output
For each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).

Sample Input
5
1 1
2 1
3 1
1 1

Sample Output
3
2
3
4
4

給你一顆樹結構,求任意結點到其他結點的路徑最大值

思路:(樹形動態規劃)

1.首先,我們先畫出一個樹結構
在這裏插入圖片描述
2.運用我們所學過的知識,建構好一顆樹之後(注意這裏不是完全二叉樹,可能有多分支),可以輕鬆用DFS求得某個結點到他的分支的最大值
如圖中2爲根到葉結點9的路徑會比2->4的大得多(假設邊權值爲1)。
我們現在確實求得了2在這棵樹上能到的最大距離,但是別忘了,12這個結點也可以到9上,這樣使得12的最遠距離也是12->9

3.通過以上例子,發現一個點的最遠距離不外乎兩種情況:
1.最遠距離是到它葉子節點距離。如2->9 、 1->9。
2.最遠距離是它“往回走”到別的結點的最遠距離。這裏可以將問題分解成父節點方向的最遠距離 + 該節點與父節點的距離。

那麼,這就有了比較和選擇,便有了狀態轉移。
首先,我們記錄一下每個節點到葉結點的最遠路的路徑。用 idx[root] = to,表示當前root結點要去最遠路,走的下一個結點是to。因爲到時我選擇“往回走”的路的時候,可以是往回走一步,走去次最遠路(舉個例子,如果2->5的邊長是100其他邊都是1,那5這個結點的最遠路是5->2->3->4,100+1+1)。所以我們前面DFS的時候同時記錄一條次最長路。

還有一種情況就是父節點再往父節點走,再去別的結點。像12->9這種路,那麼每次比較完的時候,都要記錄下這種情況。這個下面細講。

好,我們整理一下。
對上面列舉的兩種情況第一類,到子葉結點的最遠路,我們記作dp[i][0],同時記錄次短路dp[i][1]。
對於第二類,有三種情況。我們以dp[i][2]記錄該節點往回走能到的最遠路
1.如果當前結點已經是dp[i][0]上的點(也就是前面說的idx[root]==to,to是當前結點,root是父節點),那麼往回走的最遠路就是走回父節點,然後去次最長路dp【father】【1】,或者再往回走——等等!換句話說,就是找父節點往回走的路,這不就是 dp【father】【2】的意思嗎?而當前結點遍歷到的時候,dp【father】【2】也已經保存了最優解了。而如果當前結點不是最遠路,那麼兩者的判斷就是dp【father】【0】和dp【father】【2】!
那麼它的狀態轉移方程就是

dp[des][2]=max(dp[root][2],idx[root]==des?dp[root][1]:dp[root][0])+p[root][i].val;

des表示當前結點,root是父節點,p[root][i].val是兩點距離。

最後再對每個點比較dp【i】【0~2】即可

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <cmath>
#include <string>
#define maxn 10000+500
using namespace std;

typedef struct tree
{
    int to;
    int val;
} T;

vector<T> p[maxn];
int path[maxn];
int dp[maxn][4], idx[maxn];
void dfs1(int root)
{
    for(int i=0; i<p[root].size(); i++)
    {
        int  des = p[root][i].to;
        dfs1(des);
        if(dp[root][0] < dp[des][0] + p[root][i].val)
        {
            dp[root][0] =  dp[des][0] + p[root][i].val;
            idx[root] = des;
        }
    }
    for(int i=0; i<p[root].size(); i++)
    {
        int  des = p[root][i].to;
        if(idx[root]==des)  continue;
        if(dp[root][1] < dp[des][0] + p[root][i].val)
        {
            dp[root][1] =  dp[des][0] + p[root][i].val;
        }
    }

}

void dfs2(int root)
{
    for(int i=0; i<p[root].size(); i++)
    {
        int des = p[root][i].to;
        dp[des][2]=max(dp[root][2],idx[root]==des?dp[root][1]:dp[root][0])+p[root][i].val;
        dfs2(des);
    }


}

int main()
{
    int n;
    while(cin>>n)
    {
        memset(dp,0,sizeof(dp));
        memset(idx,0,sizeof(idx));
        for(int i=0; i<=n; i++)
            p[i].clear();
        for(int i=2; i<=n; i++)
        {
            int x,dis;
            cin>>x>>dis;
            T tmp;      
            tmp.to = i;
            tmp.val = dis;
            p[x].push_back(tmp);
        }
        dfs1(1);
        dp[1][2] = 0;
        dfs2(1);
        for(int i=1; i<=n; i++)
            printf("%d\n",max(dp[i][0],dp[i][2]));
    }

    return 0;
}

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