NOI-砝码称重v2 多重背包 生成函数

描述 
设有1g、2g、3g、5g、10g、20g的砝码各若干枚(其总重<=100,000),要求:计算用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况。

输入 
一行,包括六个正整数a1,a2,a3,a4,a5,a6,表示1g砝码有a1个,2g砝码有a2个,……,20g砝码有a6个。相邻两个整数之间用单个空格隔开。 
输出 
以“Total=N”的形式输出,其中N为可以称出的不同重量的个数。 
样例输入 
1 1 0 0 0 0 
样例输出 
Total=3 
提示 

样例给出的砝码可以称出1g,2g,3g三种不同的重量。 


思路: 我们看到每种砝码有num[i]个   如何做这道题呢

我们考虑背包

有不同价值的六种物品 问我们能如何组合获得一共多少种不同的价值 背包问题换个问法

我们发现这个问题其实是把物品的价值和花费合二为一了 

对不同物品选几个 其实就能获得多少价值


如何做这道题 由于最大称重已经给出来了 我们如果考虑多重背包
那么首先需要枚举物品 

再枚举有效空间 这里的空间就是最大称重

再枚举个数
因为我有100000最大的数 也就是最多有100000个不同的称重可能
我们不妨用d[i]表示i重量称重能够称到
那么如果d[v]能够称到的话前提是d[v-个数*价值]已经称到
所以这个问题其实就是 多重背包问题


#include<bits/stdc++.h> 
using namespace std;
int a[] = {0,1,2,3,5,10,20},num[10];
bool dp[100010];
int main()
{
	int sum=0;
	for(int i=1;i<=6;i++){
		scanf("%d",&num[i]);
		sum+=num[i]*a[i];
	}
	dp[0]=1;
	for(int i=1;i<=6;i++){// 从第一个物品开始枚举 
		for(int v = sum;v>=0;v--)	// 从最大容量(其实是最大的称重量) 
			for(int j=0;j<=num[i];j++){ // 枚举个数 
				if(j*a[i]<=v&&dp[v-j*a[i]])dp[v]=1;
				/*如果这个时候j个a[i]小于v那么也就是说这个称重下不会造成数组越界 
				并且如果再v-j*a[i]的情况下可以得到 那么再dp[v]的情况
				也可以得到 因为我现在有j个a[i]
				*/ 
			}
	}
	int c=0;
	for(int i=1;i<=100010;i++)
		if(dp[i])c++;
	printf("%d\n",c);
}


还有一种方法就是用母函数求解:

  设输入的质量为w的砝码n个,则可以用母函数表示为:

  针对本题目,例如输入六种砝码(1g,2g,3g,5g,10g,20g)的个数分别为:1,2,2,0,0,1。则有:


 则最终结果就是f1*f2*f3*f4中的次数不同的项 每个不同的项前面的系数就是一共有几种方案能称到这种结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值