Vijos P1071 新年趣事之打牌

gate

背包。

设f[i]为构成重量i的方案数。

则:f[i] = f[i]+f[i-c[i]]

每次更新,记录f[i]是由哪个张牌转移过来的,为pre[i]

为了防止重复(为什么会重复?),仅在当前pre[i]不存在时更新。

且只能从不为0的状态转移过来。

最后判断f[m],

大于1则多解,小于1则无解。

从m开始找到每个pre标记为vis,最后输出没访问过的。

代码如下

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;

const int maxn = 1e6+10;
int n,m,c[maxn],f[maxn],pre[maxn];
bool vis[maxn];

int main() {
    scanf("%d%d",&m,&n);
    for(int i = 1; i <= n; i++)
        scanf("%d",&c[i]);
    f[0] = 1;
    for(int i = 1; i <= n; i++)
        for(int j = m; j >= c[i]; j--) {
            f[j] += f[j-c[i]];
            if(f[j-c[i]] && !pre[j]) pre[j] = i;
        }

    if(f[m] > 1)
        printf("-1");
    else if(f[m] == 0)
        printf("0");
    else {
        for(int j = m; pre[j]; j = j-c[pre[j]])
            vis[pre[j]] = true;
        for(int i = 1; i <= n; i++)
            if(!vis[i])
                printf("%d ",i);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/mogeko/p/11845720.html