沉浸在背包的世界里不能自拔…
多重背包在完全背包的基础上升级为每个种类的东西的数目是有限的
http://acm.hdu.edu.cn/showproblem.php?pid=2191
☝多重背包裸题
AC代码
#include<iostream>
using namespace std;
#include<string.h>
#include<algorithm>
int main()
{
int C;
int n, m;
int p[600], h[600], c[600];//原始数据存储
int w[600], v[600];//拆分后的存储
int dp[10005];
int index;
cin >> C;
while (C--)
{
int i, j;
memset(p, 0, sizeof(p));
memset(h, 0, sizeof(h));
memset(c, 0, sizeof(c));
memset(dp, 0, sizeof(dp));
memset(w, 0, sizeof(w));
memset(v, 0, sizeof(v));
cin >> n >> m;
index = 1;
for (i = 1; i <= m; i++)
{
cin >> p[i] >> h[i] >> c[i];
for (j = 1; j <= c[i]; j <<= 1)
{
v[index] = j*p[i];
w[index++] = j*h[i];
c[i] -= j;
}
if (c[i] > 0)
{
v[index] = c[i] * p[i];
w[index++] = c[i] * h[i];
}
}
/*for (i = 1; i < index; i++)
cout << v[i] << " " << w[i] << endl;*/
for (i = 1; i < index; i++)
for (j = n; j >= v[i]; j--)
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
cout << dp[n] << endl;
}
return 0;
}
下面我来说一下我对多重背包的理解,time to 胡言乱语。
这是将多重背包拆分后的相当于p,w的数组的结果。
行吧…我还不是很懂。
虽然不懂,但是也要记录一下自己的想法,就大概的意思就是想要把n[i]个物品拆分掉,最简单的方法就是把它拆分成n[i]个物品,相当于01背包,但是这样就是三重循环,一旦数目变大就会超时,所以就想到了二进制拆分,但是我觉得这样子拆分就像上面跑出来的程序一样,会不会出现那种不是一下子拿走系数个,而是只拿一个是最优解的情况呢,所以我决定去胡诌一个数据试试
o( ̄ヘ ̄o#)
这是打通我任督二脉的两组数据,突然一下子就懂了,按照这个方法拆分,总是可以凑出1~n[i],这之间的每一个数字,所以无论取几个成为最优解,都是不会遗漏的,动态规划的意义也就在这里!要说一下的就是上面第一组数据中的13是1and2and4and8(不可以)and6,6不是和1、2、4一起的!
这个多重背包问题的模板真的好厉害,完全融会贯通01背包和完全背包!
多重背包问题的模板
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<string.h>
#include<string>
using namespace std;
int c[105],w[105],num[105];
int dp[105];
int v,V,V1;
void ZeroOnePack(int c, int w)
{
for(int v = V; v >=c; v--)
{
dp[v] = max(dp[v],dp[v-c]+w);
}
}
void CompletePack(int c, int w)
{
for(int v = c; v <= V; v++)
{
dp[v] = max(dp[v],dp[v-c]+w);
}
}
void MultiplePack(int c, int w, int num)
{
if(c * num >= V)
{
CompletePack(c,w);
}
//如果总容量比这个物品的容量小,那么这个物品相当于取不完,那就是完全背包问题
else//否则就要转化成01背包
{
int k = 1;
while(k < num)
{
ZeroOnePack(k*c, k*w);
num -= k;
k <<= 1;
}
ZeroOnePack(num*c, num*w);
}
}
int main()
{
int t;
scanf("%d",&t);
int n;
int i;
while(t--)
{
scanf("%d%d",&V,&n);
for(i = 1; i <=n; i++)
{
scanf("%d%d%d",&c[i], &w[i], &num[i]);
}
memset(dp,0,sizeof(dp));
for(i = 1; i <= n; i++)
{
MultiplePack(c[i],w[i],num[i]);
}
printf("%d\n",dp[V]);
}
return 0;
}
非常强!