树形dp入门
Posted zhi-71
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树形dp入门相关的知识,希望对你有一定的参考价值。
题意:有n个人参加派对,每个人有一个“开心值”,如果某个人的直接主管参加派对,那么他将不会参加派对,问派对上所有人的“开心值”的最大总和。(注意这道题是多组输入,不然会直接wa。。QAQ)
解题思路:我们可以以按主管关系建树,dp【i】【0】为当i不去时,他的子树最大的“开心值”,设u为父节点,v为子节点,那么有dp【u】【0】+=max(dp【v】【0】,dp【v】【1】),dp【u】【1】+=dp【v】【0】;
我们假设1为该树的根节点,那么答案就为max(dp【1】【0】,dp【1】【1】)
1 #include<iostream>
2 #include<cstring>
3 #include<algorithm>
4 #include<cmath>
5 #include<vector>
6 #include<stack>
7 #include<cstdio>
8 #include<map>
9 #include<set>
10 #include<string>
11 #include<queue>
12 using namespace std;
13 #define inf 0x3f3f3f3f
14 typedef long long ll;
15 inline ll gcd(ll i,ll j){
16 return j==0?i:gcd(j,i%j);
17 }
18 inline ll lcm(ll i,ll j){
19 return i/gcd(i,j)*j;
20 }
21 const int maxn=6e3+5;
22 int dis[maxn];
23 vector<int > vec[maxn];
24 int n;
25 int dp[maxn][2];
26 void dfs(int u,int fa)
27 {
28 dp[u][1]=dis[u];
29 int l=vec[u].size();
30 for(int i=0;i<l;i++){
31 int v=vec[u][i];
32 if(v!=fa){
33 dfs(v,u);
34 dp[u][0]+=max(dp[v][0],dp[v][1]);
35 dp[u][1]+=dp[v][0];
36 }
37 }
38 }
39 int main(){
40 while(~scanf("%d",&n)){
41 for(int i=1;i<=n;i++){
42 scanf("%d",&dis[i]);
43 dp[i][0]=dp[i][1]=0;
44 vec[i].clear();
45 }
46 int u,v;
47 while(scanf("%d%d",&u,&v)){
48 if(u==0&&v==0){
49 break;
50 }
51 vec[u].push_back(v);
52 vec[v].push_back(u);
53 }
54 dfs(1,-1);
58 cout<<max(dp[1][0],dp[1][1])<<endl;
59 }
60 return 0;
61 }
题意:分别求每个叶子结点到某个结点的最大距离(推荐)
解题思路:由于使用dfs获得信息,只能先得到子节点的信息,然后才能得到父节点的信息,也就是说当更新某子节点时,无法得到该节点父节点方向的信息,所以一次dfs是没有办法得到答案的。我们可以定义状态dp【i】【0】为以i为根节点,往某子结点方向所能前进的最长距离,dp【i】【1】为次远距离(注意dp【i】【0】,和dp【i】【1】所往的子结点方向不同),dp【i】【2】为以i为源点往i的父节点方向的最大长度。设u为父节点,v为子节点,w为两结点的距离。第一次dfs从下往上
,那么有dp【u】【0】=max(dp【u】【0】,dp【v】【0】+w)。第二次dfs,从上往下,当dp【u】【0】!=dp【v】【0】+w时,有dp【v】【2】=max(dp【u】【0】,dp【u】【2】)+w,否者dp【v】【2】=max(dp【u】【1】,dp【u】【2】)+w。(对状态转移方程有疑问的可以画图理解)
最后依次输出max(dp【i】【0】,dp【i】【2】);
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
typedef long long ll;
inline ll gcd(ll i,ll j){
return j==0?i:gcd(j,i%j);
}
inline ll lcm(ll i,ll j){
return i/gcd(i,j)*j;
}
struct st{
int to;
int wi;
st():to(0),wi(0){}
st(int to,int wi):to(to),wi(wi){}
};
const int maxn=1e4+5;
vector<st > vec[maxn];
int dp[maxn][3];
void dfs1(int u,int fa){
dp[u][0]=0;
dp[u][1]=0;
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i].to;
int wi=vec[u][i].wi;
if(v!=fa){
dfs1(v,u);
int tem=dp[v][0]+wi;
if(tem>dp[u][0]){
dp[u][1]=dp[u][0];
dp[u][0]=tem;
}
else if(tem>dp[u][1]){
dp[u][1]=tem;
}
}
}
}
void dfs2(int u,int fa){
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i].to;
int w=vec[u][i].wi;
if(v!=fa){
if(dp[u][0]!=dp[v][0]+w){
dp[v][2]=max(dp[u][0],dp[u][2])+w;
}
else{
dp[v][2]=max(dp[u][1],dp[u][2])+w;
}
dfs2(v,u);
}
}
}
int main(){
int n;
int wi,v;
while(~scanf("%d",&n)){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++){
vec[i].clear();
}
for(int i=2;i<=n;i++){
scanf("%d%d",&v,&wi);
vec[i].push_back(st(v,wi));
vec[v].push_back(st(i,wi));
}
dfs1(1,-1);
dfs2(1,-1);
for(int i=1;i<=n;i++)
printf("%d
",max(dp[i][0],dp[i][2]));
/*for(int i=1;i<=n;i++){
cout<<dp[i][0]<<" "<<dp[i][1]<<" "<<dp[i][2]<<endl;
}*/
}
return 0;
}
以上是关于树形dp入门的主要内容,如果未能解决你的问题,请参考以下文章