码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 1011 Starship Troopers星河战队(AC代码)树形dp

时间:2015-01-22 14:58:32      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:

 

这个没有考虑过多东西的代码也是AC了。

技术分享
 1 #include <iostream>
 2 #include <vector>
 3 #define limit 110
 4 using namespace std;
 5 
 6 vector<int> vect[limit];
 7 int n,m;
 8 bool vis[limit];
 9 int bug[limit],pos[limit];
10 int dp[limit][limit];
11 
12 int max(int a,int b){return a>b? a:b;}
13 void dfs(int p,int people)
14 {
15     int i,j,k,temp,leave;    
16     temp=(bug[p]+19)/20; //攻此房间需要temp个人手
17 
18     if(people>=temp)
19     {
20         for(i=temp;i<=people;i++)
21             dp[p][i]=pos[p];    //该房间p的不同人手i所对应的dp值
22         vis[p]=1;    //置为浏览过
23         leave=people-temp;    
24         for(i=0;i<(int)vect[p].size();i++)    //与此结点相连的所有结点都要遍历
25         {
26             if(vis[vect[p][i]]) continue;    //若遍历过的,则跳过
27             dfs(vect[p][i],leave);
28             for(j=people;j>=temp;j--) 
29             {
30                 for(k=1; k<=j-temp; k++)
31                     dp[p][j]=max( dp[p][j] , dp[p][j-k]+dp[vect[p][i]][k] ); 
32             }
33         }
34     }
35 }
36 int main()
37 {
38     int i;
39     int u,v;
40     while(scanf("%d%d",&n,&m),n!=-1||m!=-1)    //洞穴数目 人手
41     {
42         for(i=0; i<n; i++) 
43             vect[i].clear();
44         memset(dp,0,sizeof(dp));    //清内存
45         memset(vis,0,sizeof(vis));    //清内存
46         for(i=0; i<n; i++)
47             scanf("%d %d",&bug[i],&pos[i]);    //房间里的bug数、可能性
48             
49         for(i=1; i<n; i++)            //连通情况
50         {
51             scanf("%d%d",&u,&v);
52             vect[u-1].push_back(v-1);
53             vect[v-1].push_back(u-1);
54         }
55         if(m==0) {printf("0\n");continue;}
56         dfs(0,m);
57         printf("%d\n",dp[0][m]);
58     }
59     return 0;
60 }
1011

 

题意

有n个洞穴编号为1~n,洞穴间有通道,形成了一个n-1条边的树, 洞穴的入口即根节点是1。
每个洞穴有x只bugs,并有价值y的金子,全部消灭完一个洞穴的虫子,就可以获得这个洞穴的y个金子.
现在要派m个战士去找金子,从入口进入。每次只有消灭完当前洞穴的所有虫子,才可以选择进入下一个洞穴。
一个战士可以消灭20只虫子,如果要杀死x只虫子,那么要x/20向上取整即(x+19)/20个战士。
如果要获得某个洞穴的金子,必须留下足够杀死所有虫子的战士数量, 即(x+19)/20个战士,然后这些留下战士就不能再去其它洞穴
其他战士可以继续走去其它洞穴,可以选择分组去不同的洞穴。
战士只能往洞穴深处走,不能走回头路
问最多能获得多少金子?

要特别注意的是,如果是叶子节点,并且叶子节点的花费为0,那么要让他的花费变为1,因为必须派一个战士走向叶子节点才可以获得金子,但此战士不能往上走了,只能往下走,也许再碰到一个bug数为0的洞就可以捡金子了,要是一路往下都是bug为0,一路捡下去都行。

 

 

下面给个考虑多一点的AC代码。

技术分享
 1 #include <iostream>
 2 #include <vector>
 3 #define limit 110
 4 using namespace std;
 5 
 6 vector<int> vect[limit];
 7 int n,m;
 8 bool vis[limit];
 9 int bug[limit],pos[limit];
10 int dp[limit][limit];
11 
12 int max(int a,int b){return a>b? a:b;}
13 void dfs(int p,int people)
14 {
15     int i,j,k,temp,leave;    
16     temp=(bug[p]+19)/20; //攻此房间需要temp个人手
17 
18     if(people>=temp)    //假如people=0,temp=0,那应该如何?没人手,又想捡人头
19     {    
20         if(people==0&&temp==0)    return;    //应该这么解决!都不可能派给此洞人手,下面的行为还有必要吗?
21         for(i=temp;i<=people;i++)
22             dp[p][i]=pos[p];
23         vis[p]=1;    //置为浏览过
24         leave=people-temp;    
25         for(i=0;i<(int)vect[p].size();i++)    //与此结点相连的所有结点都要遍历
26         {
27             if(vis[vect[p][i]]) continue;    //若浏览过的,则跳过
28             dfs(vect[p][i],leave);
29             for(j=people;j>=temp;j--) 
30             {
31                 for(k=1; k<=j-temp; k++)
32                     dp[p][j]=max( dp[p][j] , dp[p][j-k]+dp[vect[p][i]][k] ); 
33             }
34         }
35     }
36 }
37 int main()
38 {
39     int i;
40     int u,v;
41     while(scanf("%d%d",&n,&m),n!=-1||m!=-1)    
42     {
43         for(i=0; i<n; i++) 
44             vect[i].clear();
45         memset(dp,0,sizeof(dp));    //清内存
46     memset(vis,0,sizeof(vis));    //清内存
47         for(i=0; i<n; i++)
48             scanf("%d %d",&bug[i],&pos[i]);    //房间里的bug数、金子
49             
50         for(i=1; i<n; i++)            //连通情况
51         {
52             scanf("%d%d",&u,&v);
53             vect[u-1].push_back(v-1);
54         vect[v-1].push_back(u-1);
55         }
56         if(m==0) {printf("0\n");continue;}
57         dfs(0,m);
58         printf("%d\n",dp[0][m]);
59     }
60     return 0;
61 }
1011

 

下面是我想了很久却不明白之处:在接收“边”的时候,把每条边设为无向边,即把每个结点设想为带若干通向其孩子的边+带一条通向父亲的边。此题的遍历方式是从上往下,即从根结点开始,那么在遍历一个结点x的时候,其vector容器中vect[x]中就会有一个父亲结点的编号,刚从父亲递归下来的,父亲肯定被置为遍历过了,却还需要在vect[x]中当遇到遍历过的结点时就跳过。此举不是多余吗?vis数组的意义在哪?

我认为应该是这样的代码:

技术分享
 1 #include <iostream>
 2 #include <vector>
 3 #define limit 110
 4 using namespace std;
 5 
 6 vector<int> vect[limit];
 7 int n,m;
 8 //bool vis[limit];
 9 int bug[limit],pos[limit];
10 int dp[limit][limit];
11 
12 int max(int a,int b){return a>b? a:b;}
13 void dfs(int p,int people)
14 {
15     int i,j,k,temp,leave;    
16     temp=(bug[p]+19)/20; //攻此房间需要temp个人手
17 
18     if(people>=temp)    //假如people=0,temp=0,那应该如何?没人手,又想捡人头
19     {    
20         if(people==0&&temp==0)    return;    //应该这么解决!都不可能派给此洞人手,下面的行为还有必要吗?
21         for(i=temp;i<=people;i++)
22             dp[p][i]=pos[p];
23         //vis[p]=1;    //置为浏览过
24         leave=people-temp;    
25         for(i=0;i<(int)vect[p].size();i++)   
26         {
27         //    if(vis[vect[p][i]]) continue;    //若浏览过的,则跳过
28             dfs(vect[p][i],leave);
29             for(j=people;j>=temp;j--) 
30             {
31                 for(k=1; k<=j-temp; k++)
32                     dp[p][j]=max( dp[p][j] , dp[p][j-k]+dp[vect[p][i]][k] );  
33             }
34         }
35     }
36 }
37 int main()
38 {
39     int i;
40     int u,v;
41     while(scanf("%d%d",&n,&m),n!=-1||m!=-1)    
42     {
43         for(i=0; i<n; i++) 
44             vect[i].clear();
45         memset(dp,0,sizeof(dp));    //清内存
46     //    memset(vis,0,sizeof(vis)); 
47         for(i=0; i<n; i++)
48             scanf("%d %d",&bug[i],&pos[i]);    
49             
50         for(i=1; i<n; i++)    
51         {
52             scanf("%d%d",&u,&v);
53             vect[u-1].push_back(v-1);
54         //    vect[v-1].push_back(u-1);
55         }
56         if(m==0) {printf("0\n");continue;}
57         dfs(0,m);
58         printf("%d\n",dp[0][m]);
59     }
60     return 0;
61 }
1011

但是其结果是WA,这实在令人难接受啊!这就好像你吃饭时特意拿个碗去装了菜,到最后这盘菜都没动过一口,还得洗碗!

 

HDU 1011 Starship Troopers星河战队(AC代码)树形dp

标签:

原文地址:http://www.cnblogs.com/xcw0754/p/4241459.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!