hdu 2191

本文探讨了一种特定类型的背包问题,并提供了详细的解决方案。针对不同情况下的背包容量,文章介绍了如何通过二进制优化来减少时间复杂度,同时给出了具体的实现代码。通过对完全背包和01背包的比较,展示了如何在有限的背包容量内实现价值最大化。

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

题目概述:

有times组数据

背包大小lim,有kind种物品

每种物品大小c,价值v,有n个

输入:

第一行times,下一行lim,kind,其后kind行,每行c,v,n,多组数据之间没有空行

输出:

每行一个数,包能装的最大价值

样例输入:

3

8 2

2 100 4

4 100 2

14 3

2 100 4

4 100 2

1 100 3

13 3

2 100 4

4 100 2

1 100 2

样例输出:

400

700

600

讨论:

No STL的胜利,容器,I/O,函数操作统统没有STL,代价就是下面那个十万的pro数组,其实只需要lim+1的大小足矣,不过这样省去了resize+fill+clear的老套逻辑(偶尔还可能伴随out of range异常)了

两个背包的函数模版原来是嵌套在里面的,不过为了方便区分和日后复习,就抠出来了

由于之前有了完全背包和01背包的两道水题,因此这个题其实全当是在研究如何用二进制优化,仔细想想,用意不大

1.如果包的容量装不下所有物品,转化为01背包,这里用二进制把多个同种物品合并了一下,降低一点时间复杂度,但对渐进复杂度没有改进,代码反而复杂不少,这类题同种物一般没太多,这样反而容易出错,只是用作一种参考,省的以后不知道还有这个方法

2.如果包的容量能装下所有物品,转化为完全背包,一直在想能不能也把这个按指数合并一下,算了吧,没太大改进

题解状态:

0MS,1800K,1490B,G++


#include<cmath>
#include<cctype>
#include<cstring>
#include<algorithm>
#include<numeric>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<list>
#include<stack>
using namespace std;

struct item//每种物品的数据类型
{
	int v;
	int c;
	int n;
};
item items[105];//装所有物品数据的容器
int pro[100005];//执行背包算法的容器
inline int maxx(int a, int b)//求两个数最大值
{
	return a > b ? a : b;
}
inline void pack01(int *pro, item item, int lim, int scale)//01背包模版
{
	for (int i = lim; i >= item.c*scale; i--) {
		pro[i] = maxx(pro[i], i - item.c*scale >= 0 ? pro[i - item.c*scale] + item.v*scale : 0);
	}
}
inline void packcompleted(int *pro, item item, int lim)//完全背包模版
{
	for (int i = item.c; i <= lim; i++) {
		pro[i] = maxx(pro[i], i - item.c >= 0 ? pro[i - item.c] + item.v : 0);
	}
}
int fun(int lim, int kind)
{
	int v, c, n;
	for (int p = 0; p < kind; p++) {
		scanf("%d%d%d", &c, &v, &n);//input
		items[p].v = v;
		items[p].c = c;
		items[p].n = n;
	}//input
	for (int p = 0; p < kind; p++) {
		if (items[p].c*items[p].n < lim) {//参见讨论1
			int u = 1;
			while (u <= items[p].n) {
				pack01(pro, items[p], lim, u);
				items[p].n -= u;
				u *= 2;
			}
			pack01(pro, items[p], lim, items[p].n);
		} else {//参见讨论2
			packcompleted(pro, items[p], lim);
		}
	}
	return pro[lim];
}
int main(void)
{
	//freopen("vs_cin.txt", "r", stdin);

	int times;
	scanf("%d", &times);//input
	while (times--) {
		int lim, kind;
		~scanf("%d%d", &lim, &kind);//input
		printf("%d\n", fun(lim, kind));//output
		memset(pro, 0, sizeof(pro));//虽说装物品的数组不用清空,但是执行操作的需要清空
	}
}
EOF


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值