凑硬币
题目描述
jyb 想给他的女朋友买一块很贵的巧克力,jyb 有 n个硬币,第 i 个硬币的价值为 ci 元,巧克力的价格为 k。jyb 想用一些硬币凑出恰好 k元为他的女朋友买一块巧克力。
看着他的硬币,他想到了一个问题,假设他不给女朋友巧克力,而是给她 k元的硬币,她用这恰好 k元的硬币可以凑出哪些价值呢?他想不出来,于是请你帮他解答这个问题。
更准确地说,jyb 想要知道所有的价值 x,在 jyb 的硬币中能够找出一个恰好 k 元的子集 S,使得存在 S 的子集 S2,S2硬币价值的和是 x。显然 0和 k都是符合条件的 x。
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
Solution
由于恰好K元的子集可能有多个, 且题目要求只能使用同一子集中的元素凑硬币
所以设 表示在满足恰好元的若干子集中, 可以由其中一个集合中元素凑出元
Code
#include<bits/stdc++.h>
#define reg register
const int maxn = 1005;
int N, K;
int A[maxn], dp[maxn][maxn];
int main(){
freopen("coin.in", "r", stdin);
freopen("coin.out", "w", stdout);
scanf("%d%d", &N, &K);
for(reg int i = 1; i <= N; i ++) scanf("%d", &A[i]);
dp[0][0] = 1;
for(reg int i = 1; i <= N; i ++)
for(reg int j = K; j >= 0; j --)
for(reg int t = j; t >= 0; t --){
dp[j+A[i]][t+A[i]] |= dp[j][t];
dp[j+A[i]][t] |= dp[j][t];
}
/*
for(reg int i = 1; i <= N; i ++)
for(reg int j = K+A[i]; j >= A[i]; j --)
for(reg int t = j; t >= A[i]; t --)
dp[j][t] |= dp[j-A[i]][t-A[i]],
dp[j][t] |= dp[j-A[i]][t];
*/
int cnt = 0;
for(reg int i = 0; i <= K; i ++) cnt += dp[K][i];
printf("%d\n", cnt);
for(reg int i = 0; i <= K; i ++)
if(dp[K][i]) printf("%d ", i);
return 0;
}