程设模拟考 D:硬币

题目见此:http://cxsjsx.openjudge.cn/2013weekend/5D/

解题思路:

  1. 一看就是背包问题,但要求算必须使用的,第一反应时枚举去掉每一种物品,看看能不能拼出V,结果超时(必然的)
  2. 正确思路是,当判断第i个物品是否必要时,只需判断前i-1种物品和后i+1至N种物品凑起来能否拼出V即可
  3. 因此在这个思路下,我们首先要保存二维数组,便于提取中间结果,而且要注意使前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 }
View Code


这题虽然过了,思路也正确,但数据不是最优:

Accepted 16008kB 40ms 974 B

G++

可以改为一位数组,极大减少空间复杂度,比如我室友写的:

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 }
View Code

 

posted on 2013-06-16 15:42  白~  阅读(210)  评论(0编辑  收藏  举报

导航