程设模拟考 D:硬币
题目见此:http://cxsjsx.openjudge.cn/2013weekend/5D/
解题思路:
- 一看就是背包问题,但要求算必须使用的,第一反应时枚举去掉每一种物品,看看能不能拼出V,结果超时(必然的)
- 正确思路是,当判断第i个物品是否必要时,只需判断前i-1种物品和后i+1至N种物品凑起来能否拼出V即可
- 因此在这个思路下,我们首先要保存二维数组,便于提取中间结果,而且要注意使前i-1物品花费的空间+后面物品花费的空间和要为V
贴代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <set> 4 using namespace std; 5 6 const int MAXN = 210, MAXV = 10010; 7 int f1[MAXN][MAXV] = {0}, f2[MAXN][MAXV] = {0}, c1[MAXN], c2[MAXN], N, V; 8 int main() 9 { 10 set<int> S; 11 cin >> N >> V; 12 for(int i=1 ; i<=N ; i++) 13 { 14 cin >> c1[i]; 15 c2[N-i+1] = c1[i]; 16 } 17 for(int i=1 ; i<=N ; i++) 18 for(int j=V ; j>=0 ; j--) 19 { 20 f2[i][j] = f2[i-1][j]; 21 if(j >= c2[i]) 22 f2[i][j] = max(f2[i-1][j], f2[i-1][j-c2[i]]+c2[i]); 23 } 24 int count = 0; 25 for(int i=1 ; i<=N ; i++) 26 { 27 bool f = 0; 28 for(int j=V ; j>=0 ; j--) 29 { 30 f1[i][j] = f1[i-1][j]; 31 if(j >= c1[i]) 32 f1[i][j] = max(f1[i-1][j], f1[i-1][j-c1[i]]+c1[i]); 33 if(f == 0 && f1[i-1][j] + f2[N-i][V-j] == V) 34 { 35 f = 1; 36 count++; 37 } 38 } 39 if(f == 0) 40 S.insert(i); 41 } 42 cout << N - count << endl; 43 bool f = 0; 44 for(set<int>::iterator it=S.begin() ; it!=S.end() ; it++) 45 if(f == 0) 46 { 47 cout << c1[*it]; 48 f = 1; 49 } 50 else 51 cout << " " << c1[*it]; 52 cout << endl; 53 }
这题虽然过了,思路也正确,但数据不是最优:
Accepted | 16008kB | 40ms | 974 B |
可以改为一位数组,极大减少空间复杂度,比如我室友写的:
Accepted | 480kB | 40ms | 815 B | G++ |
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 5 using namespace std; 6 7 int c[220000],f2[2000000],f1[2000000]; 8 9 int main() 10 { 11 12 int n,x; 13 cin>>n>>x; 14 for (int i=1;i<=n;i++) 15 cin>>c[i]; 16 f1[0]=1; 17 for (int i=1;i<=n;i++) 18 for (int j=x;j>=c[i];j--) 19 f1[j]+=f1[j-c[i]]; 20 f2[0]=1; 21 int ans[2010],ansn=0; 22 memset(ans,0,sizeof(ans)); 23 for(int i = 1;i<=n; i++) 24 { 25 if (i>1) 26 for (int j=x;j>=c[i-1];j--) 27 f2[j]+=f2[j-c[i-1]]; 28 for (int j=c[i];j<=x;j++) 29 f1[j]-=f1[j-c[i]]; 30 bool is=false; 31 for(int j = 0; j <= x; j++) 32 if(f2[j]&&f1[x-j]) 33 { 34 is=true; 35 break; 36 } 37 if(is) continue; 38 else ans[ansn++]=c[i]; 39 } 40 printf("%d\n",ansn); 41 if(ansn) 42 cout<<ans[0]; 43 for(int i = 1; i < ansn; i++) 44 printf(" %d",ans[i]); 45 printf("\n"); 46 return 0; 47 }