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

HDU 2196 Computer(樹形dp)

核心想法:

我們把1固定為這棵樹的根節點。 對於一棵樹上的任意子節點,我們可以把樹分割為兩部分: 以2為例,一部分是以2為根節點的樹,一部分是以2的父節點(1)為根節點的樹,這時候,2要到達這棵大樹的葉節點就有兩種途徑。

  1. 節點在左邊的小樹裡 ,直接往下走到底。其中走的最長的距離記為dp[i][0]
  2. 節點在右邊的小樹裡 先走到父節點的位置,再從父節點走到底。其中走的最長的距離記為dp[i][1]

接下來的事情就分為兩個步驟,求每個節點的dp[i][0]和dp[i][1],最後輸出較大的那個就行了。

求dp[i][0]

以1為為根節點遞迴跑一遍dfs,一次解決所有的節點的dp[i][0]。

求dp[i][1]

注意:因為要用到父節點的資料,所以dfs2(爹)求的是它所有子節點的dp[i號兒子][1],而非dp[爹][1]!!!

找node節點最長的支線,長為max1,和第二長的支線,長為max2。設該子節點到父節點的距離為w。

  1. 假如node的子節點不在最長支線上:dp[子節點][1]=max1+w
  2. 假如node的子節點在最長支線上:dp[子節點][1]=max2+w

接下來就是求max1和max2: 分兩種情況(圖中的node指的是傳給dfs2()的序號,是父節點,實際要求的是它的兒子們)

在這裡插入圖片描述 1、node沒爹(node=1) max1和max2就在所有以node為根節點的支路里找最長的兩個。 換句話說就是在dp[子節點][0]+w

裡找最大的兩個。

2、node有爹 max1和max2的比較中,除了所有支路,還要再加上dp[node][1] 一起比較

程式碼如下

//hdu 2196
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
struct Node
{
    int f,l;
};
long long dp[10005][2];
bool vis[10005];
vector<Node>
son[10005]; void dfs1(int root)//算所有節點只帶枝葉的那半邊 { vis[root]=true; for(int i=0;i<son[root].size();i++) { int v=son[root][i].f; if(!vis[v]) { dfs1(v); dp[root][0]=max(dp[root][0],dp[v][0]+son[root][i].l); } } } void dfs2(int node)//算node的子節點加上根節點的那半邊 { int max1=0,max2=0,v1,v2; vis[node]=true; for(int i=0;i<son[node].size();i++)//找node最長兩個子節點 { int v=son[node][i].f; int w=son[node][i].l; if(!vis[v]) { int temp=dp[v][0]+w; if(temp>max1) { max2=max1; max1=temp; v1=v; } else if(temp==max1||temp>max2) { max2=temp; } } } if(node!=1)//和node帶父節點的比較,找最大兩個 { int temp=dp[node][1]; if(temp>max1) { max2=max1; max1=temp; v2=v1; v1=-1; } else if(temp==max1||temp>max2) { max2=temp; v2=-1; } } for(int i=0;i<son[node].size();i++)//判斷該子節點是不是最長枝葉上的 { int v=son[node][i].f; int w=son[node][i].l; if(vis[v]) continue; if(v==v1) dp[v][1]=max2+w; else dp[v][1]=max1+w; dfs2(v); } } int main() { freopen("input","r",stdin); freopen("output","w",stdout); int n; while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) son[i].clear(); for(int i=2;i<=n;i++) { int f,l; scanf("%d %d",&f,&l); son[i].push_back((Node){f,l}); son[f].push_back((Node){i,l}); } memset(dp,0,sizeof(dp)); memset(vis,false,sizeof(vis)); dfs1(1); memset(vis,false,sizeof(vis)); dfs2(1); for(int i=1;i<=n;i++) cout<<max(dp[i][0],dp[i][1])<<endl; } return 0; }