题目概述:
有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", ×);//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