CodeForces - 687C The Values You Can Make ——dp

题意: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;
}

猜你喜欢

转载自blog.csdn.net/hao_zong_yin/article/details/80165751