HDU2844(多重背包)

本文介绍了一种解决多重背包问题的方法,特别关注如何在给定不同类型货币及其数量的情况下,计算出可以组成的货币总额数目。通过使用优化后的DP算法,有效地解决了问题,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意:给你n个种类的钱和对应的数量,同统计一下从1到m能够凑成的钱有多少个;

解题思路:多重背包的题,少了一个类似于重量上限的限制,这里其实就是那个m,每次不断变化的1到m的值就是限制,最后统计下多少dp数组更新过就是能够凑到的,这里不用从1到m枚举上限,直接上限填m,这样在更新完n个种类后m之前由于要到达m必然解决比他小的包,简言之,就是前面的dp已经优化了(你想我们既然都优化到m了,像m-1,m-2,m-3...2,1这些是不是都优化了),以下模板。(ps:HDOJ这题我交了一个有BUG的代码上去居然AC了,虽然是998ms

AC代码如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<queue>
#include<map>
#include<math.h>
using namespace std;

const int inf=0x3f3f3f3f;
const int maxn=1e5+10;

int dp[maxn],value[110],num[110];

int max(int a,int b)
{
	return a>b?a:b;
}
//每次最大值会更新
void pack01(int v,int h,int m)
{
	for(int i=m;i>=v;i--)
		dp[i]=max(dp[i],dp[i-v]+h);
	return ;
}

void packall(int v,int h,int m)
{
	for(int i=v;i<=m;i++)
		dp[i]=max(dp[i],dp[i-v]+h);
	return ;
}

void packs(int v,int h,int m,int cnt)
{
	if(cnt*v>=m)
	{
		packall(v,h,m);
		return ;
	}
	int k=1;
	while(k<=cnt)
	{
		pack01(k*v,k*h,m);  //更新物品的比例
		cnt-=k;  //二进制思路压缩背包物品的数量
		k<<=1;
	}
	if(cnt)
		pack01(cnt*v,cnt*h,m);  //最后一件
	return ;
}
/*
dp[i]:不超过i的合成的最大的钱
*/
int main()
{
	int n,m,cnt,i,j;
	while(cin>>n>>m && n+m)
	{
		dp[0]=cnt=0;
		for(i=1;i<=m;i++)
			dp[i]=-inf;
		for(i=0;i<n;i++)
			cin>>value[i];
		for(i=0;i<n;i++)
			cin>>num[i];
		for(j=0;j<n;j++)
			packs(value[j],value[j],m,num[j]);
		for(i=1;i<=m;i++)
			if(dp[i]>0)
				cnt++;
		cout<<cnt<<endl;
	}
	return 0;
}

View Code

Problem : 2844 ( Coins )     Judge Status : Accepted
RunId : 23886175    Language : C++   
Code Render Status : Rendered By HDOJ C++ Code Render Version 0.01 Beta
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<queue>
#include<map>
#include<math.h>
using namespace std;

const int inf=0x3f3f3f3f;
const int maxn=1e5+10;

int dp[maxn],value[110],num[110];

int max(int a,int b)
{
    return a>b?a:b;
}
//每次最大值会更新
void pack01(int v,int h,int m)
{
    for(int i=m;i>=v;i--)
        dp[i]=max(dp[i],dp[i-v]+h);
    return ;
}

void packall(int v,int h,int m)
{
    for(int i=v;i<=m;i++)
        dp[i]=max(dp[i],dp[i-v]+h);
    return ;
}

void packs(int v,int h,int m,int cnt)
{
    if(cnt*v>=m)
    {
        packall(v,h,m);
        return ;
    }
    int k=1;
    while(k<=cnt)
    {
        pack01(k*v,k*h,m);  //更新物品的比例
        cnt-=k;  //二进制思路压缩背包物品的数量
        k<<1;  //bug的地方
    }
    pack01(cnt*v,cnt*h,m);  //最后一件
    return ;
}
/*
dp[i]:不超过i的合成的最大的钱
*/
int main()
{
    int n,m,cnt,i,j;
    while(cin>>n>>m && n+m)
    {
        dp[0]=cnt=0;
        for(i=1;i<=m;i++)
            dp[i]=-inf;
        for(i=0;i<n;i++)
            cin>>value[i];
        for(i=0;i<n;i++)
            cin>>num[i];
        for(j=0;j<n;j++)
            packs(value[j],value[j],m,num[j]);
        for(i=1;i<=m;i++)
            if(dp[i]>0)
                cnt++;
        cout<<cnt<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小胡同的诗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值