標籤:
題目大意: 求樹中每個點到所有葉子節點的距離的最大值是多少。
思路: 這個題用兩邊dfs就可以,一遍是求當前點到子樹那個方向上的最大值和次大值,另外一遍是父親方向上的最大值。之所以要求子樹方向上的次大值,是因為如果求當前點v的最長的距離的時候,子樹裡面的顯而易見可以求出來,但是父親方向上的就不確定了,如果父親的取最大值的路徑經過點v,那麼這樣求肯定就不對了,所以要求一個次大值,這時,用父親的次大值加上父親的權值和子樹方向上的比較就行了。
代碼如下:
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 11000;struct Edge { int to, Next, len;};Edge edge[maxn * 2];int tot, head[maxn];int maxlen[maxn], smaxlen[maxn];//maxlen當前節點的子樹的最大值 smaxlen次大值 int maxid[maxn], smaxid[maxn];//maxid當前節點取最大值時都應的兒子編號, smaxid次大值時對應的編號 void init(){ memset(head, -1, sizeof(head)); tot = 0;}void addedge(int u, int v, int len){ edge[tot].to = v; edge[tot].len = len; edge[tot].Next = head[u]; head[u] = tot++;}//找出每一個節點往下的最大值和次大值 void dfs1(int u, int fa)//求出以u為根節點的最大距離 { maxlen[u] = smaxlen[u] = 0; for (int i = head[u]; i != -1; i = edge[i].Next) { int v = edge[i].to; if (v == fa) continue; dfs1(v, u); if (smaxlen[u] < maxlen[v] + edge[i].len) { smaxlen[u] = maxlen[v] + edge[i].len; smaxid[u] = v; if (maxlen[u] < smaxlen[u]) { swap(maxlen[u], smaxlen[u]); swap(maxid[u], smaxid[u]); } } }}//找出從父節點過來和從當前點向下的最大值 void dfs2(int u, int fa){ for (int i = head[u]; i != -1; i = edge[i].Next) { int v = edge[i].to; if (v == fa) continue; if (v == maxid[u])//這裡求的是v的而不是u的,和dfs1區分開,所以如果u取最大值時如果經過v的話,那麼算從u過來的路徑時要用次大值 { if (edge[i].len + smaxlen[u] > smaxlen[v]) { smaxlen[v] = edge[i].len + smaxlen[u]; smaxid[v] = u; if (maxlen[v] < smaxlen[v]) { swap(maxlen[v], smaxlen[v]); swap(maxid[v], smaxid[v]); } } } else//否則用最大值 { if (edge[i].len + maxlen[u] > smaxlen[v]) { smaxlen[v] = edge[i].len + maxlen[u]; smaxid[v] = u; if (maxlen[v] < smaxlen[v]) { swap(maxlen[v], smaxlen[v]); swap(maxid[v], smaxid[v]); } } } dfs2(v, u); }}int main(){ int n; while (~scanf("%d", &n)) { init(); int a, b; for (int i = 2; i <= n; i++) { scanf("%d %d", &a, &b); addedge(i, a, b); addedge(a, i, b); } dfs1(1, 0); dfs2(1, 0); for (int i = 1; i <= n; i++) printf("%d\n", maxlen[i]); } return 0;}
HDU 2196 Computer(樹形dp)