多重背包一
有 N 种物品和一个容量是 V 的背包。
第 i 种物品最多有 si 件,每件体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤100
0<vi,wi,si≤100
输入样例
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出样例:
10
【问题分析】
可以将s[i]件物品拆分成单个物品,则问题转化为01背包问题。由于n<=100,si<=100,因此相当于为100*100件物品进行01背包,可以暴力解决。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int v[10000],w[10000],s[10000],f[10000],n,m,i,j,k;
int main ()
{
cin>>n>>m;
for (i=1; i<=n; i++)
cin>>v[i]>>w[i]>>s[i];
for (i=1; i<=n; i++)
for (j=m; j>=0; j--)
for (k=1; k<=s[i]; k++)
{
if (j-k*v[i]<0) break;
f[j]=max(f[j-k*v[i]]+w[i]*k,f[j]);
}
cout<<f[m];
}
【特别注意初始化与求解】
1、若初始化f[i]=0,则求的是f[m];如上面的代码;
2、若初始化f[0]=0,f[i]=-INF&&i!=0,则求解的是max(f[i]);
多重背包二
庆功会(party,1s,128M)
【问题描述】为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。
【输入格式】
第一行二个数n(n<=500),m(m<=6000),其中n代表希望购买的奖品的种数,m表示拨款金额。
接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和购买的数量(买0件到s件均可),其中v<=1000,w<=1000,s<=1000。
【输出格式】
第一行:一个数,表示此次购买能获得的最大的价值(注意!不是价格)。
【输入样例】
5 1000
80 20 4
40 50 9
30 50 7
40 30 6
20 20 1
【输出样例】
1040
【问题解析】
看数据规模可知使用上面的方法将s件物品拆分成单个物品进行01背包处理会超时,那么如何进行优化呢?
可以将s件物品进行二进制拆分;
我们可以把十件物品A分成若干份,这若干份必须可以组合成0~10以内的任何一个数字。
做法是:1,2,4,…,2(k-1),10-2k+1
即:10可以分为 1,2,4,3
显然这四个数字,可以组合成0~10以内的任何一个数字,如 8 = 1 + 4 + 3
每一份对应的体积和价值,用系数乘以1件物品的体积和价值。
这么做的好处,可以把时间复杂度从O(nm)降为O(m log n),剩下的继续用01背包问题的解法求解。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int v[10001],w[10001],n,m,n1;
int f[6001];
int main ()
{
cin>>n>>m;
for (int i=1; i<=n; i++)
{
int x,y,s,t=1;
cin>>x>>y>>s;
while(s>=t)//构建1,2,...,2^(k-1)为系数的各个数据
{
v[++n1]=x*t;
w[n1]=y*t;
s-=t;
t*=2;
}
v[++n1]=x*s;//构建s[i]-2^k+1为系数的数据
w[n1]=y*s;
}
for(int i=1;i<=n1;i++)//0-1背包
for(int j=m;j>=v[i];j--)
f[j]=max(f[j],f[j-v[i]]+w[i]);
cout<<f[m];
}
视频讲解
多重背包
二维费用背包
潜水员
【问题描述】
潜水员为了潜水要使用特殊的装备。他有一个带2种气体的气缸:一个为氧气,一个为氮气。让潜水员下潜的深度需要各种的数量的氧和氮。潜水员有一定数量的气缸。每个气缸都有重量和气体容量。潜水员为了完成他的工作需要特定数量的氧和氮。他完成工作所需气缸的总重的最低限度的是多少?
例如:潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
如果潜水员需要5升的氧和60升的氮则总重最小为249(1,2或者4,5号气缸)。
你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。
【输入格式】
第一行有2整数m,n(1<=m<=21,1<=n<=79)。它们表示氧,氮各自需要的量。
第二行为整数k(1<=n<=1000)表示气缸的个数。
此后的k行,每行包括ai,bi,ci(1<=ai<=21,1<=bi<=79,1<=ci<=800)3整数。这些各自是:第i个气缸里的氧和氮的容量及汽缸重量。
【输出格式】
仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。
【样例输入】
5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
【样例输出】
249
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int a[10000],b[10000],c[10000],f[5000][5000];
int main ()
{
int i,j,n,m,k,t,s,l,ma;
cin>>n>>m;
cin>>k;
memset(f,1000001,sizeof(f));
f[0][0]=0;
for (i=1; i<=k; i++)
cin>>a[i]>>b[i]>>c[i];
for (i=1; i<=k; i++)
for (j=n; j>=0; j--)
for (l=m; l>=0; l--)
{
t=j+a[i]; s=l+b[i];
t=min(n,t); s=min(m,s);
if (f[t][s]>f[j][l]+c[i]) f[t][s]=f[j][l]+c[i];
}
cout<<f[n][m];
}
视频讲解
二维费用背包