暑假- 动态规划 I-(N - Coins)

/*
多重背包问题:一般化为01背包[逆序]和完全背包[顺序]来求解
多重背包优化:二进制原理。
dp[i]表示:容量为i的背包在限制条件下[硬币的面值和数量]所能获得的最大值
此题中的每个硬币的体积[重量]和价值[面值]是同一个数[a]。
当dp[i]==i时,表示容量为i的背包可以装下价值为i的物品,即相当于能够用所限的
硬币凑足i。最后再扫一遍数组就能得出结果。
*/
#include<iostream>
using namespace std;
const int MAXN=100005;
struct Node 
{
	int a;
	int c;
};
int dp[MAXN];
int mymax(int a,int b)
{
	return a>b?a:b;
}
void CompletePack(int w,int m)//完全背包(顺序求解,w即使重量也是价值)
{
	for(int i=w;i<=m;i++)
	{
		dp[i]=mymax(dp[i],dp[i-w]+w);
	}
}
void ZeroOnePack(int w,int m)//01背包(逆序求解,w即使重量也是价值)
{
	for(int i=m;i>=w;i--)
	{
		dp[i]=mymax(dp[i],dp[i-w]+w);
	}
}
void MultiPack(int w,int c,int m)
{
	if(w*c>=m)//面值*数目〉所要凑得面值(相当于有无限多个面值为w的硬币可用)
	{
		CompletePack(w,m);//多重背包-->完全背包
	}
	else//否则,多重背包-->01背包
	{   //二进制原理转换成01背包求解。
		int k=1;
		while(c-k>0)
		{
			ZeroOnePack(w*k,m);
			c-=k;
			k*=2;
		}
		ZeroOnePack(w*c,m);//剩下的硬币数目
	}
}
int main()
{
	int n,m;
	while(cin>>n>>m)
	{
		if(!n&&!m)
		{
			break;
		}
		int temp=0;//统计能凑齐的数目
		Node p[105];
		memset(dp,0,sizeof(dp));
		for(int i=0;i<n;i++)//录入面值
		{
			cin>>p[i].a;
		}
		for(int i=0;i<n;i++)//录入数目
		{
			cin>>p[i].c;
		}
		for(int i=0;i<n;i++)
		{
			MultiPack(p[i].a,p[i].c,m);
		}
		for(int i=1;i<=m;i++)//扫描统计
		{
			if(dp[i]==i)
			{
				temp++;
			}
		}
		cout<<temp<<endl;
	}
	return 0;
}


一般将多重背包转换成01背包和完全背包求解。

多重背包问题:二进制原理,单调队列。

                           

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值