HDU 2191悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包基础题)


                                 HDU2191悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包)

http://acm.hdu.edu.cn/showproblem.php?pid=2191

题意:

       假设你有资金n元, 然后有m种大米, 每种大米价格为cost[i], 重量为val[i], 数量为num[i]. 现在有n元钱,去买大米,求大米的最大重量。

分析:

       本题是典型的多重背包问题.(背包容量为总金额n元,物体体积为单价,价值为物体的重量)

       dp[i][j]:表示购买前i种大米,且总费用<=j时能购买的大米最大重量.

       边界控制: dp为全0.

       由于每种大米有数量num[i], 所以我们分下面两种情况做:

       cost[i]*num[i]>=n(容量*个数>=背包容量), 我们直接对该种大米做一次完全背包过程即可.

       cost[i]*num[i]<n, 我们把num[i]个第i类大米看成下面k+1种物品:

       1个(i类物品)  2个 4个 2^(k-1)个 以及 num[i]-2^k+1个

       我们对上述k+1种新物品每个都做一个01背包即可覆盖我们可能对第i种物品做出的所有选择(2进制哟).

       最终所求: dp[m][n]的值.


AC代码:

   

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n, m;//总金额和大米种类
int cost[105], value[105], num[105];//价格 重量 数量
int dp[105];

//一次01背包
void Zero_One_Pack(int cost, int value)
{
	for (int i = n; i >= cost; i--)
		dp[i] = max(dp[i], dp[i - cost] + value);
}
//一次完全背包
void Complete_Pack(int cost, int value)
{
	for (int i = cost; i <= n; i++)
		dp[i] = max(dp[i], dp[i - cost] + value);	
}

//一次多重背包
void Multi_Pack(int cost, int val, int num)
{
	if (cost*num >= n)
	{
		Complete_Pack(cost, val); return;
	}
	int k = 1;
	while (k < num)
	{
		Zero_One_Pack(k*cost, k*val);
		num -= k;
		k *= 2;
	}
	Zero_One_Pack(num*cost, num*val);
}
int main()
{
	int T; cin >> T;
	while (T--)
	{
		cin >> n >> m;
		for (int i = 1; i <= m; i++)
		  cin >> cost[i] >> value[i] >> num[i];		
		memset(dp, 0, sizeof(dp));
		for (int i = 1; i <= m; i++)
			Multi_Pack(cost[i], value[i], num[i]);
		cout << dp[n] << endl;
	}
	system("pause");
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值