1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <math.h> 4 #include <algorithm> 5 #include <stdlib.h> 6 #include <vector> 7 #include <map> 8 #include <queue> 9 #include <string> 10 #include <iostream> 11 #include <ctype.h> 12 #include <string.h> 13 #include <set> 14 #include <stack> 15 #include<functional> 16 using namespace std; 17 #define size 100001 18 #define maxn 1<<30 19 int dp[size]; 20 int dpn[size]; 21 int a[205], ans[205]; 22 /* 23 dp是一个滚动数组dp[j]表示j块钱可以用钱币组成的数目 24 dpn也是一个滚动数组表示不用第i种钱可以组成j块钱的数目 25 dp[j]=dp[j]+dp[j-a[i]] 26 有两种可能性,一种是不用第i个钱币,那么他的数目就等于dp[i-1][j] 也就是dp[j] 27 意思是使用第i个钱币,那么他的数目就等于dp[j-a[i]]; 28 dp[0]=1; 其他初始化为0; 29 30 31 当可以选第i件钱币时 32 dpn[j]=dp[j]-dpn[j-a[i]] 33 当j-a[i]<0 34 那本来就不能选择第i个钱币 35 dpn[j]=dp[j] 36 37 出口dpn[0]=1 当j==a[i]时会出现也就是说,把单独这一个情况排除就好,也就是减去1种只有这一个钱币组成的情况 38 39 40 注意两次更新的内层循环的顺序 41 */ 42 int main(){ 43 44 int n, x; 45 cin >> n >> x; 46 for (int i = 1; i <= n; i++){ 47 scanf("%d", &a[i]); 48 } 49 dp[0] = dpn[0] = 1; 50 for (int i = 1; i <= n; i++) 51 for (int j = x; j >= a[i]; j--){ 52 dp[j] = dp[j] + dp[j - a[i]];//因为实际上需要的是dp[i-1][j] 那么内层循环要倒序更新 53 } 54 int pos = 0; 55 for (int i = 1; i <= n; i++) 56 { 57 for (int j = 0; j <=x; j++){ 58 if (j - a[i] >= 0) 59 dpn[j] = dp[j] - dpn[j - a[i]];//因为不是滚动数组没有倒序更新的必要了 60 else 61 dpn[j] = dp[j];//而且应该是先填充dpn[j]较小的部分,要是倒序更新,第一遍dpn[j-a[i]]等于1,0,0,0 并不是我们所需要的dpn[j] 62 } 63 if (dpn[x] == 0) ans[pos++] = a[i]; 64 } 65 cout << pos << endl; 66 if(pos) cout << ans[0]; 67 else cout <<endl; 68 for (int i = 1; i < pos; i++) 69 cout << " "<<ans[i]; 70 cout << endl; 71 system("pause"); 72 return 0; 73 }