貌似是很经典的树形dp问题,应该说是树形dp的入门!!

感觉树形dp比背包多了一个辅助数组,背包直接一个数组循环下去,而树形dp因为有分支,不是线性的,所以就需要用一个辅助数组来进行转化最优情况!

1011 题目大意:一棵树,有n个结点,每个结点有v个bug,有w的brain。我从1号结点开始走,带着m个战士。
1个战士可以消灭20个bugs,如果我把某个结点的所有bug都消灭了我就能得到那个结点的brain。
如果想攻击当前结点,那么必须先攻击了它的父结点(1号点除外)。
其中当你攻占了当前结点,你可以分派人手,走向几个不同的子结点,去攻占更多。也就是说,不是单一的路径。
代码:
 1 # include<stdio.h>
2 # include<string.h>
3 # define N 105
4 struct node{
5 int from,to,next;
6 }edge[2*N];
7 int head[N],tol,visit[N],ans[N],bug[N],n,m,dp[N][N],f[N][N];
8 void add(int a,int b)
9 {
10 edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++;
11 }
12 int max(int a,int b)
13 {
14 return a>b?a:b;
15 }
16 void dfs(int u)
17 {
18 int i,j,r,tt,k;
19 visit[u]=1;
20 for(i=head[u];i!=-1;i=edge[i].next)
21 {
22 r=edge[i].to;
23 if(!visit[r])
24 {
25 dfs(r);
26 for(k=m;k>=1;k--)
27 {
28 for(j=1;j<=k;j++)
29 {
30 f[u][k]=max(f[u][k],f[u][k-j]+dp[r][j]);
31 }
32 }
33 /*for(j=0;j<=m;j++)
34 {
35 if(j*20>=ans[u])
36 dp[u][j]=max(dp[u][j],dp[r][(j*20-ans[u])/20]+bug[u]);
37 }*/
38 }
39 }
40 tt=(ans[u]+19)/20;
41 for(j=tt;j<=m;j++)
42 dp[u][j]=f[u][j-tt]+bug[u];
43 }
44 int main()
45 {
46 int i,a,b;
47 while(scanf("%d%d",&n,&m)!=EOF)
48 {
49 if(n==-1 && m==-1) break;
50 for(i=1;i<=n;i++)
51 scanf("%d%d",&ans[i],&bug[i]);
52 tol=0;
53 memset(head,-1,sizeof(head));
54 for(i=1;i<n;i++)
55 {
56 scanf("%d%d",&a,&b);
57 add(a,b);
58 add(b,a);
59 }
60 memset(visit,0,sizeof(visit));
61 memset(dp,0,sizeof(dp));
62 memset(f,0,sizeof(f));
63 if(m==0)
64 {
65 printf("0\n");
66 continue;
67 }
68
69 dfs(1);
70 printf("%d\n",dp[1][m]);
71 }
72 return 0;
73 }


 1561 The more, The Better

 题目意思不再解释!

根据题意建立有向树,父亲节点优于孩子节点(必须先攻占父亲节点才能攻占孩子节点)!

以0为树根,求最优解的方法和上题一样,只不过最后要求的是dp[0][m+1];

开始我没想到把0作为根,那样就会有很多棵树,分别求出每棵树的最优解,然后背包一次,也不错!!

代码:

View Code
 1 # include<stdio.h>
2 # include<string.h>
3 # define N 205
4 int n,m;
5 struct node{
6 int from,to,next;
7 }edge[N];
8 int tol,head[N],visit[N],ans[N],dp[N][N],f[N][N];
9 void add(int a,int b)
10 {
11 edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++;
12 }
13 int max(int a,int b)
14 {
15 return a>b?a:b;
16 }
17 void dfs(int root)
18 {
19 int j,u,k,i;
20 visit[root]=1;
21 for(i=head[root];i!=-1;i=edge[i].next)
22 {
23 u=edge[i].to;
24 if(!visit[u])
25 {
26 dfs(u);
27 for(k=m;k>=0;k--)
28 for(j=0;j<=k;j++)
29 f[root][k]=max(f[root][k],f[root][k-j]+dp[u][j]);
30 }
31 }
32 for(j=1;j<=m+1;j++)
33 dp[root][j]=f[root][j-1]+ans[root];
34 }
35 int main()
36 {
37 int i,a,b;
38 while(scanf("%d%d",&n,&m)!=EOF)
39 {
40 if(n==0 && m==0) break;
41 tol=0;
42 memset(head,-1,sizeof(head));
43 for(i=1;i<=n;i++)
44 {
45 scanf("%d%d",&a,&b);
46 ans[i]=b;
47 add(a,i);
48 }
49 ans[0]=0;
50 memset(visit,0,sizeof(visit));
51 memset(dp,0,sizeof(dp));
52 memset(f,0,sizeof(f));
53 dfs(0);
54 printf("%d\n",dp[0][m+1]);
55 }
56 return 0;
57 }
posted on 2011-07-19 19:58  奋斗青春  阅读(2823)  评论(1编辑  收藏  举报