HDU_2844 Coins ( dp | 多重背包问题 )

文章目录

题目连接 hdu or vj

题意

给定商品种类 n, 以及背包容量 m
每组数据的第二行 前n个是对应物品价值, 后n个是对应物品数量,
问 有多少种可能使得背包容量 等于 1,m 这个 区间的数

这是另一种表述方法,
有n种货币, 已知每种货币的价值和数量, 问这些货币能够恰好构成1~m的几种情况

题解

先记录一个坑点 … 数组开小了, 会超时, 从头到尾找了半天, 真是太弟弟了

多重背包板子题, 给定了物品的数量限制条件, 很自然就会想到多重背包了

再注意一点的是这里题意的问法比较绕, 实际上就是问遍历 1,m 看看 看看 i==dpi] 的个数

感觉这个题题意需要仔细反复读, 难点是理解问的什么

代码

#include <bits/stdc++.h> 
using namespace std; 
#define sc scanf 
#define pf printf 
typedef long long ll; 

const int maxn = 1e2+100;
const int maxm = 1e5+100;;

int val[maxn], num[maxn],
    dp[maxm],
    n, m;

void ZeroOnePack ( int val, int wei ) {
	for ( int i = m; i >= val; --i )
		dp[i] = max ( dp[i], dp[i - val] + wei );
}
void CompletePack ( int val, int wei ) {
	for ( int i = val; i <= m; ++i )
		dp[i] = max ( dp[i], dp[i - val] + wei );
}
void MultiplePack ( int val[], int wei[], int num[] ) {
	for ( int i = 0; i < n; ++i ) {
		if ( val[i] * num[i] >= m ) {
			CompletePack ( val[i], wei[i] );
		}
		else {
			int k = 1;
			while ( k < num[i] ) {
				ZeroOnePack ( k * val[i], k * wei[i] );
				num[i] -= k;
				k <<= 2;
			}
			ZeroOnePack ( num[i] * val[i], num[i] * wei[i] );
		}
	}
}

int main ( ) {

    while ( ~sc ( "%d %d", &n, &m ) ) {
        if ( n == 0 && m == 0 ) break;

        for ( int i = 0; i < n; ++i ) sc ( "%d", &val[i] );
        for ( int j = 0; j < n; ++j ) sc ( "%d", &num[j] );

        memset ( dp, 0, sizeof ( dp ) );

        MultiplePack ( val, val, num );

        int cnt = 0;
        for ( int i = 1; i <= m; ++i )
            if ( dp[i] == i )cnt++;

        pf ( "%d\n", cnt );
    }

	return 0;
}
/* 
3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0 
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值