ZOJ 3211 Dream City(DP)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3374
题目大意:JAVAMAN 到梦幻城市旅游见到了黄金树,黄金树上每天回结出金子。已经有n棵树,JAVAMAN要停留m天,每天只能砍掉一棵树,砍掉树后就能得到树上的黄金。给定n棵树上原有的黄金a[i]和每天可以新增加的黄金b[i],求他最多可以得到多少黄金。中途如果有1天不砍树的话,之后的日子久不能砍树,所有最好每天都砍树,或者直到树被砍完。
Sample Input
2
2 1
10 10
1 1
2 2
8 10
2 3
Sample Output
10
21
Hints:
Test case 1: JAVAMAN just cut tree 1 to get 10 gold coins at the first day.
Test case 2: JAVAMAN cut tree 1 at the first day and tree 2 at the second day to get 8 + 10 + 3 = 21 gold coins in all.
分析:凭借经验每天结果子越多的树越在最后砍,能得到最大收益。所以开始按照b[i]由小到大排序。
令dp[i][j]表示在前 i 棵树中 j 天的最大收益,则答案为dp[n][m],很像背包。
代码如下:
1 # include<iostream> 2 # include<cstdio> 3 # include<cstring> 4 # include<algorithm> 5 using namespace std; 6 7 int n,m; 8 struct node 9 { 10 int a,b; 11 } s[255]; 12 int dp[255][255]; 13 bool cmp(const node a,const node b) 14 { 15 return a.b < b.b; 16 } 17 18 int main() 19 { 20 int T,i; 21 scanf("%d",&T); 22 while(T--) 23 { 24 scanf("%d%d",&n,&m); 25 for(i=1; i<=n; i++) 26 scanf("%d",&s[i].a); 27 for(i=1; i<=n; i++) 28 scanf("%d",&s[i].b); 29 sort(s+1,s+1+n,cmp); 30 memset(dp,0,sizeof(dp)); 31 for(int i =1; i<=n; i++) 32 { 33 for(int j=1; j<=m; j++) 34 { 35 dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]+s[i].a+(j-1)*s[i].b); 36 } 37 } 38 printf("%d\n",dp[n][m]); 39 } 40 return 0; 41 }
这道题目最开始脑子里想的是记忆化搜索,却写成了DFS,结果当然超时。
1 # include<iostream> 2 # include<cstdio> 3 # include<cstring> 4 using namespace std; 5 6 int n,m,maxx; 7 int a[255],b[255],vis[255]; 8 9 void DP(int x,int y) 10 { 11 if(x > maxx) 12 maxx = x; 13 if(y > m) 14 return ; 15 int i; 16 for(i=1; i<=n; i++) 17 { 18 if(vis[i]) continue;; 19 vis[i] = 1; 20 DP(x+a[i]+(y-1)*b[i],y+1); 21 vis[i] = 0; 22 } 23 } 24 int main() 25 { 26 int T,i; 27 scanf("%d",&T); 28 while(T--) 29 { 30 scanf("%d%d",&n,&m); 31 for(i=1; i<=n; i++) 32 scanf("%d",&a[i]); 33 for(i=1; i<=n; i++) 34 scanf("%d",&b[i]); 35 maxx = 0; 36 DP(0,1); 37 printf("%d\n",maxx); 38 } 39 return 0; 40 }
这里为什么混淆呢?总结以下几点
1.DFS和记忆化搜索都用到了新开的数组vis[]表示是否遍历过
2.DFS中会vis[i]=1表示走过,之后还会vis[i]=0还原回来,但是记忆化搜索没有这个回溯的过程
3.一般情况下,如果求n所对应的结果,DFS是从1开始,而记忆化搜索从结果开始,因为它只遍历一次