HDU 2196 Computer(樹形dp)
阿新 • • 發佈:2018-12-16
核心想法:
我們把1固定為這棵樹的根節點。 對於一棵樹上的任意子節點,我們可以把樹分割為兩部分: 以2為例,一部分是以2為根節點的樹,一部分是以2的父節點(1)為根節點的樹,這時候,2要到達這棵大樹的葉節點就有兩種途徑。
- 節點在左邊的小樹裡 ,直接往下走到底。其中走的最長的距離記為dp[i][0]。
- 節點在右邊的小樹裡 先走到父節點的位置,再從父節點走到底。其中走的最長的距離記為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。
- 假如node的子節點不在最長支線上:dp[子節點][1]=max1+w
- 假如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;
}