这个没有考虑过多东西的代码也是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,这实在令人难接受啊!这就好像你吃饭时特意拿个碗去装了菜,到最后这盘菜都没动过一口,还得洗碗!
时间: 2024-10-14 20:18:59