1. 程式人生 > >HDU-2196 Computer (樹形DP)

HDU-2196 Computer (樹形DP)

color const discuss amp mem [] 應該 str col

最近在看樹形DP,這題應該是樹形DP的經典題了,寫完以後還是有點感覺的。之後看了discuss可以用樹分治來做,以後再試一試。



題目大意

找到帶權樹上離每個點的最遠點。︿( ̄︶ ̄)︿


題解:

對於每一個點的最遠點,就是以這個點為根到所有葉子節點的最長距離。但是如果確定根的話,除了根節點外,只能找到每個節點(度數-1)個子樹的最大值,剩下一個子樹是該節點當前的父親節點。

所以當前節點的最遠點在當前節點子樹的所有葉子節點以及父親節點的最遠點上(當父親節點的最遠點不在當前節點的子樹上時),

如果父親節點的最遠點在當前子樹上時候,取父親節點的第二大最遠點子樹上。(具體的看代碼)

#include <cstdio>
#include 
<iostream> #include <algorithm> #include <cstring> #define MAX_NUM 10020 #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long int LL; struct no { LL v,next,w; }edge[4*MAX_NUM]; int stu[MAX_NUM]; int col = 0; void add(LL u , LL v,LL w){ edge[col].v
= v; edge[col].w = w; edge[col].next = stu[u]; stu[u] = col++; } LL dp[MAX_NUM][2]; LL sec[MAX_NUM]; LL sett[MAX_NUM]; bool flag[MAX_NUM]; LL fdfs(LL u){ dp[u][0] = 0; for (int i = stu[u]; i != -1 ; i = edge[i].next){ LL v = edge[i].v; if(!flag[v]){ flag[v]
= true; LL num = fdfs(v)+edge[i].w; if(num>=dp[u][0]){ sec[u] = dp[u][0]; dp[u][0] = num; sett[u] = v; } else if(num>=sec[u]){ sec[u] = num; } } } return dp[u][0]; } void ddfs(LL u){ for (int i = stu[u]; i != -1 ; i = edge[i].next){ LL v = edge[i].v; if(!flag[v]){ flag[v] = true; if(sett[u]!=v) dp[v][1] = max(dp[u][0], dp[u][1])+edge[i].w; else dp[v][1] = max(sec[u],dp[u][1])+edge[i].w; ddfs(v); } } } int main(int argc, char const *argv[]) { int n; while(~scanf("%d",&n)){ mem(dp,0); mem(flag,false); mem(sett,0); mem(stu,-1); mem(sec,-1); LL a,b; col = 0; for (int i = 2; i <= n ; ++i) { scanf("%lld%lld",&a,&b); add(i,a,b); add(a,i,b); } flag[1] = true; fdfs(1); mem(flag,false); flag[1] = true; ddfs(1); for (int i = 1; i <= n ; ++i) { printf("%lld\n",max(dp[i][0],dp[i][1])); } } return 0; }

HDU-2196 Computer (樹形DP)