题干:
描述
小Q手里有n枚硬币,每枚硬币有一定的金额x,他想知道,用这些硬币能组成多少种不同的金额。但是他太笨了,自己数懵了,你来帮帮他好不好?
注意:组成金额时,每枚硬币只能用一次,但可以同时使用等面值的不同硬币
输入
第一行 n,表示第二行一共有n个数字
第二行 n个数字,表示不同的硬币的面值
单组输入,不用担心
输出
第一行 输出 m, 表示可以组成多少种不同的金额
第二行 按照从小到大的顺序输出所有的金额。
注意,每行的结尾,不要有空格,否则你的答案可能会被判错。
输入样例 1
2 1 2
输出样例 1
3 1 2 3
输入样例 2
2 1 1
输出样例 2
2 1 2
提示
n<=1000, x>=1&&x<=200
解题报告:
不难看出这是道组合数学的题目,解决这类问题(凑种数)有两种方式,背包类dp或者是母函数,这里选用了装满类0-1背包来解决这道题,母函数以后可以自己试试?(这个数据范围应该是够了)
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int dp[5000000 + 5],v[5000000 + 5],ans[5000000 + 5];
int sum;
int main()
{
int n;
cin>>n;
for(int i = 1; i<=n; i++) scanf("%d",v+i),sum += v[i];
dp[0]=0;
for(int i = 1; i<=200000; i++) dp[i] = -INF;
for(int i = 1; i<=n; i++) {
for(int j = sum; j>=v[i]; j--) {
dp[j] = max(dp[j],dp[j-v[i]] + v[i]);
}
}
int cnt = 0;
for(int i = 1; i<=200000; i++) {
if(dp[i] >= 0) {
cnt++;
ans[cnt] = i;
}
}
printf("%d\n",cnt);
for(int i = 1; i<=cnt; i++) {
printf("%d",ans[i]);
if(i!=cnt ) putchar(' ');
}
return 0 ;
}
//5
//100 100
//100
//100
//100
总结:
没有错,刚开始wa了这么多发,就是因为背包写错了,没加那个max、、、话说啊不到半个月没写背包你就忘这么干净了?