题意:n个硬币,每个硬币有一个价值a【i】, 定义S为价值总和为k的硬币的集合,首先求出所有S, 然后对于每一个S,将S中的硬币能组成的所有金额放到集合ans中,最后按照升序输出ans中的所有元素
思路:定义dp【t】【i】【j】表示选了前t个硬币,金额为i,是否能用前i个硬币的子集组成金额j,初始化为dp【0】【0】【0】=false,转移采用刷表法,用dp【t】【i】【j】去推dp【t+1】【i+a【t】】【j】和dp【t+1】【i+a【t】】【j+a【t】】,最终答案就是使dp【n】【k】【i:1~k】为true的那些i
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> using namespace std; const int maxn = 510; int n, k, a[maxn]; bool dp[maxn][maxn]; vector<int> ans; int main() { scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); memset(dp, false, sizeof(dp)); dp[0][0] = true; for (int t = 1; t <= n; t++) { for (int i = k - a[t]; i >= 0; i--) { for (int j = 0; j <= k - a[t]; j++) { if (dp[i][j]) dp[i+a[t]][j] = dp[i+a[t]][j+a[t]] = true; } } } ans.clear(); for (int i = 0; i <= k; i++) if (dp[k][i]) ans.push_back(i); printf("%d\n%d", ans.size(), ans[0]); for (int i = 1; i < ans.size(); i++) printf(" %d", ans[i]); printf("\n"); return 0; }