树形DP专题

hdu 1520  Anniversary party

分析:要求不跟自己的上司或下属在一起即根不与其孩子同时选择。

dp[i][0]表示i为根且根不选获得的最大值,则其值为孩子结点选择与不选的最大值

即dp[i][0]=max(dp[son][0],dp[son][1]);

dp[i][1]表示i为根且选择获得的最大值,则其孩子结点不能选择dp[i][1]=sum{dp[son][0]};

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxlen 6010
 5 using namespace std;
 6 struct node
 7 {
 8     int to,next,w;
 9 }edge[maxlen*2];
10 int head[maxlen];
11 int num;
12 int dp[maxlen][2];
13 bool used[maxlen];
14 int c[maxlen];
15 void init()
16 {
17     num=0;
18     memset(head,-1,sizeof(head));
19     memset(used,false,sizeof(used));
20     memset(dp,0,sizeof(dp));
21     memset(c,0,sizeof(c));
22 }
23 void addedge(int u,int v,int w)
24 {
25     edge[num].to=v;
26     edge[num].w=w;
27     edge[num].next=head[u];
28     head[u]=num++;
29     edge[num].to=u;
30     edge[num].w=w;
31     edge[num].next=head[v];
32     head[v]=num++;
33 }
34 void dfs(int u)
35 {
36     if(used[u])
37         return ;
38     used[u]=true;
39     dp[u][1]=c[u];
40     for(int i=head[u];i!=-1;i=edge[i].next)
41     {
42         int v=edge[i].to;
43         if(!used[v])
44         {
45             dfs(v);
46             dp[u][0]+=max(dp[v][0],dp[v][1]);
47             dp[u][1]+=dp[v][0];
48         }
49     }
50 }
51 int main ()
52 {
53     int n,x,y;
54     while(scanf("%d",&n)!=EOF)
55     {
56         init();
57         for(int i=1;i<=n;++i)
58             scanf("%d",&c[i]);
59         while(scanf("%d%d",&x,&y))
60         {
61             if(x==0&&y==0)
62                 break;
63             addedge(x,y,0);
64         }
65         dfs(1);
66         int ans=max(dp[1][0],dp[1][1]);
67         printf("%d
",ans);
68     }
69 }
View Code

hdu 1561 The more, The Better

 增加一个权值为0的0号节点使整个成为一棵树,接下来就是0-1背包的问题了

dp[u][j]表示u为根节点选择j个获得的最大价值,根节点必须选择,然后其他可以

从孩子节点中选择。

dp[u][j]=max{dp[u][j],dp[son][j-k]+dp[u][k]}

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxlen 210
 5 using namespace std;
 6 bool used[maxlen];
 7 int cost[maxlen];
 8 int maps[maxlen][maxlen];
 9 int num[maxlen];
10 int dp[maxlen][maxlen];
11 int n,m;
12 void dfs(int x)
13 {
14     used[x]=true;
15     for(int i=1;i<=num[x];++i)
16     {
17         int u=maps[x][i];
18         if(!used[u])
19             dfs(u);
20         for(int j=m;j>=2;--j)
21         {
22             for(int k=1;k<j;++k)
23             {
24                 if(dp[x][k]!=-1&&dp[u][j-k]!=-1&&used[u])
25                 dp[x][j]=max(dp[x][j],dp[x][k]+dp[u][j-k]);
26             }
27         }
28     }
29 
30 }
31 int main ()
32 {
33     while(scanf("%d%d",&n,&m)!=EOF)
34     {
35         if(n==0&&m==0)
36             break;
37         m++;//添加一个编号为0权值为0的点,这个顶点必须选
38         dp[0][1]=cost[0]=0;
39         memset(maps,0,sizeof(maps));
40         memset(num,0,sizeof(num));
41         memset(used,0,sizeof(used));
42         for(int i=1;i<=n;++i)
43         {
44             int x,y;
45             scanf("%d%d",&x,&y);
46             maps[x][++num[x]]=i;
47             cost[i]=y;
48         }
49         for(int i=0;i<=n;++i)
50         {
51             dp[i][0]=0;
52             dp[i][1]=cost[i];
53             for(int j=2;j<=m;++j)
54             {
55                 dp[i][j]=-1;
56             }
57         }
58         dfs(0);
59         printf("%d
",dp[0][m]);
60     }
61 }
View Code

hdu 2196 Computer

要求输出对于每一个结点的树上任意结点到该点的最大距离。

需要两次dfs,第一次dfs是更新该结点的孩子结点到它的距离,需要记录最大值以及次大值。

另一个dfs是更新从父节点过来的最大值,之所以需要记录次小值是因为如果只存最大值的话,

判断一个点的从父节点过来的最大值,那么如果他的父节点存的最大值正好是从该点过来的,

那么就失去了从父节点过来的状态,所以要记录最大的两个值。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define maxlen 10010
  6 using namespace std;
  7 struct node
  8 {
  9     int to,next,w;
 10 }edge[maxlen*2];
 11 int head[maxlen];
 12 int num;
 13 int maxnum[maxlen];
 14 int smaxnum[maxlen];
 15 int maxid[maxlen];
 16 int smaxid[maxlen];
 17 void init()
 18 {
 19     num=0;
 20     memset(head,-1,sizeof(head));
 21 }
 22 void addedge(int u,int v,int w)
 23 {
 24     edge[num].to=v;
 25     edge[num].w=w;
 26     edge[num].next=head[u];
 27     head[u]=num++;
 28     edge[num].to=u;
 29     edge[num].w=w;
 30     edge[num].next=head[v];
 31     head[v]=num++;
 32 }
 33 void dfs(int u,int father)
 34 {
 35     maxnum[u]=smaxnum[u]=0;
 36     for(int i=head[u];i!=-1;i=edge[i].next)
 37     {
 38         int v= edge[i].to;
 39         if(v==father)
 40             continue;
 41         dfs(v,u);
 42         if(smaxnum[u]<maxnum[v]+edge[i].w)
 43         {
 44             smaxnum[u]=maxnum[v]+edge[i].w;
 45             smaxid[u]=v;
 46             if(smaxnum[u]>maxnum[u])
 47             {
 48                 swap(smaxnum[u],maxnum[u]);
 49                 swap(smaxid[u],maxid[u]);
 50             }
 51         }
 52     }
 53 }
 54 void dfs2(int u,int father)
 55 {
 56     for(int i=head[u];i!=-1;i=edge[i].next)
 57     {
 58         int v=edge[i].to;
 59         if(v==father)
 60             continue;
 61         //dfs2(v,u);
 62         if(v==maxid[u])
 63         {
 64             if(edge[i].w+smaxnum[u]>smaxnum[v])
 65             {
 66                 smaxnum[v]=edge[i].w+smaxnum[u];
 67                 smaxid[v]=u;
 68                 if(smaxnum[v]>maxnum[v])
 69                 {
 70                     swap(smaxnum[v],maxnum[v]);
 71                     swap(smaxid[v],maxid[v]);
 72                 }
 73             }
 74         }
 75         else
 76         {
 77             if(edge[i].w+maxnum[u]>smaxnum[v])
 78             {
 79                 smaxnum[v]=edge[i].w+maxnum[u];
 80                 smaxid[v] = u;
 81                 if(smaxnum[v]>maxnum[v])
 82                 {
 83                     swap(smaxnum[v],maxnum[v]);
 84                     swap(smaxid[v],maxid[v]);
 85                 }
 86             }
 87         }
 88         dfs2(v,u);
 89     }
 90 }
 91 int main ()
 92 {
 93     int n,v,w;
 94     while(scanf("%d",&n)!=EOF)
 95     {
 96         init();
 97         for(int i=2;i<=n;++i)
 98         {
 99             scanf("%d%d",&v,&w);
100             addedge(i,v,w);
101         }
102         dfs(1,-1);
103         dfs2(1,-1);
104         for(int i=1;i<=n;++i)
105             printf("%d
",maxnum[i]);
106     }
107 
108 }
View Code

hdu 4276 The Ghost Blows Light  2012 ACM/ICPC Asia Regional Changchun Online

分析:首先根据题目意思从1到n的路径是必须要走的,所以我们可以先求出1到n的最短路径然后把这条路径

的权值改为0使接下来的dp一定会选择这些点。

dp[u][j]表示u为根使用j的时间可以获得的最大值,由于最短的路径且这条路径走也只能走一次才能最短,

所以其他的路径都是分支,走过去还是需要回来的,所以花费的时间w是单次的两遍(往返)

方程为dp[u][j] = max{dp[u][j],dp[son][k]+dp[u][j-k-w]}  j>=k+w  

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #define maxlen 610
 5 using namespace std;
 6 struct node
 7 {
 8     int to,next,w;
 9 }edge[maxlen*2];
10 int head[maxlen];
11 int num;
12 int n,t;
13 int dp[maxlen][maxlen];
14 int c[maxlen];
15 bool used[maxlen];
16 int sum;
17 void init()
18 {
19     num=0;
20     memset(head,-1,sizeof(head));
21     memset(used,0,sizeof(used));
22     memset(dp,0,sizeof(dp));
23     memset(c,0,sizeof(c));
24 }
25 void addedge(int u,int v,int w)
26 {
27     edge[num].to=v;
28     edge[num].w=w;
29     edge[num].next=head[u];
30     head[u]=num++;
31     edge[num].to=u;
32     edge[num].w=w;
33     edge[num].next=head[v];
34     head[v]=num++;
35 }
36 bool short_path(int u,int father)
37 {
38     if(u==n)
39         return true;
40     for(int i=head[u];i!=-1;i=edge[i].next)
41     {
42         int v=edge[i].to;
43         if(v==father)
44             continue;
45         if(short_path(v,u))
46         {
47             sum+=edge[i].w;
48             edge[i].w=0;
49             return true;
50         }
51     }
52     return false;
53 }
54 void dfs(int u,int father)
55 {
56     for(int i=0;i<=t;++i)
57         dp[u][i]=c[u];
58     for(int i=head[u];i!=-1;i=edge[i].next)
59     {
60         int v=edge[i].to;
61         int w=edge[i].w*2;//还要返回主干的结点,所以时间是两倍
62         if(v==father)
63             continue;
64         dfs(v,u);
65         for(int j=t;j>=w;--j)
66         {
67             for(int k=0;k<=j-w;++k)
68             {
69                 dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-w-k]);
70             }
71         }
72     }
73 }
74 int main ()
75 {
76     while(scanf("%d%d",&n,&t)!=EOF)
77     {
78         init();
79         for(int i=1;i<n;++i)
80         {
81             int x,y,w;
82             scanf("%d%d%d",&x,&y,&w);
83             addedge(x,y,w);
84         }
85         for(int i=1;i<=n;++i)
86             scanf("%d",&c[i]);
87         sum=0;
88         short_path(1,-1);
89         t-=sum;
90         if(t<0)
91             printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!
");
92         else
93         {
94             dfs(1,-1);
95             printf("%d
",dp[1][t]);
96         }
97 
98     }
99 }
View Code
原文地址:https://www.cnblogs.com/shuzy/p/3348840.html