树形dp入门

 

hdu1520

题意:有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 }

 hdu2196

题意:分别求每个叶子结点到某个结点的最大距离(推荐)

解题思路:由于使用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;
}

 

原文地址:https://www.cnblogs.com/Zhi-71/p/10323171.html