背包。
设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; }