题目链接:https://codeforces.com/problemset/problem/687/C
题目大意:给你n个数,然后让这些数相加组合,然后在这些组合的数里可以再相加组合搞出给定 k,输出这些组合的数。
Examples
Input
6 18
5 6 1 10 12 2
Output
16
0 1 2 3 5 6 7 8 10 11 12 13 15 16 17 18
Input
3 50
25 25 50
Output
3
0 25 50
emmm,实际上我们可以看到的是这些数是成对出现的,那么我们只需要对每对数进行搜寻判断就好了,如果$i,k-i$可以同时由上面的数组合而成,那么我们就可以肯定$i,k-i$是存在的,可以输出的。那么怎么判断一对数能否同时由上面的数组合而成呢?应该很容易想到背包,之前讲过的多背包问题也就在这里再一次的运用上了,定义背包状态$dp[i][j]$表示$i,j$容量的时候最大能够取得的价值,那么如果$dp[i][k-i]==k$也就是两个背包刚好都装满了。于是。。。。此题结束。。。
以下是AC代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int mac=550; int a[mac],ans[mac]; int dp[mac][mac]; int main() { int n,m; scanf ("%d%d",&n,&m); for (int i=1; i<=n; i++) scanf ("%d",&a[i]); for (int i=1; i<=n; i++) for (int j=m; j>=0; j--) for (int k=m; k>=0; k--){ if (j-a[i]>=0) dp[j][k]=max(dp[j][k],dp[j-a[i]][k]+a[i]); if (k-a[i]>=0) dp[j][k]=max(dp[j][k],dp[j][k-a[i]]+a[i]); } int cnt=0; for (int i=0; i<=(m-1)/2; i++){ if (dp[i][m-i]==m) ans[++cnt]=i,ans[++cnt]=m-i; } if (!(m&1) && dp[m/2][m/2]==m) ans[++cnt]=m/2; sort(ans+1,ans+1+cnt); printf("%d ",cnt ); for (int i=1; i<=cnt; i++) printf("%d%c",ans[i],i==cnt?' ':' '); return 0; }