【qduoj - 纳新题】凑数题(恰好装满类0-1背包 或 母函数)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/82817214

题干:

描述

小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、、、话说啊不到半个月没写背包你就忘这么干净了?

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/82817214