标准背包
说明
有一个背包能装的重量maxw(正整数,0≤maxw≤20000),同时有n件物品(0≤n≤100),每件物品有一个重量wi(正整数)和一个价值pi(正整数)。要求从这n件物品中任取若干件装入背包内,使背包的物品价值最大。
输入格式
第1行:背包最大载重maxw,物品总数n
第2行到第n+1行:每个物品的重量和价值。
输出格式
一个数字即背包内物品最大价值。
样例
输入数据 1
10 3
4 5
3 4
6 9
输出数据 1
14
#include <bits/stdc++.h>
using namespace std;
const int mm=20100;
const int mn=110;
int w[mn],p[mn];
int f[mm];
int n,m,i,j;
int main()
{
cin>>m>>n;
for(i=1;i<=n;i++) cin>>w[i]>>p[i];
for (i=0; i<=m; i++) f[i]=0;// 初值
for (i=1; i<=n; i++)
for (j=m; j>=w[i]; j--)
f[j]=max(f[j],f[j-w[i]]+p[i]);
cout<<f[m];
return 0;
}
极简背包问题
说明
极简单的背包问题。
设有一个背包,可以放入的重量为s。现有n件物品,重量分别为w_1,w_2…,w_n,(1≤i≤n)w
1
,w
2
…,w
n
,(1≤i≤n) 均为正整数,从n件物品中挑选若干件,使得放入背包的重量之和正好为s。
输入格式
第一行两个整数包括放入的物品重量为s(s<=32767)和物品的件数n(n<=50);
第二行n个整数,表示每件物品的重量(输入数据均为正整数)
输出格式
若满足条件则输出"YES",若不满足则输出"NO"。
样例
输入数据 1
20 5
1 3 5 7 9
输出数据 1
YES
#include<bits/stdc++.h>
using namespace std;
int s,n,w[51],f[51];
bool flag;
void dfs(int i,int step){
f[step] = w[i];
int sum = 0;
for(int k=1;k<=step;k++){
sum = sum + f[k];
}
if(sum==s){
flag = 1;
return;
}
for(int k=i+1;k<=n;k++){
if(flag==0 && sum<s) dfs(k,step+1);
}
}
int main(){
cin>>s>>n;
for(int i=1;i<=n;i++){
cin>>w[i];
}
for(int i=1;i<=n;i++){
memset(f,0,sizeof(f));
dfs(i,1);
if(flag==1) break;
}
if(flag==1) cout<<"YES";
else cout<<"NO";
return 0;
}
多重背包(1)
说明
有N种物品和一个容量是V的背包。
第i种物品最多有si件,每件体积是vi,价值是wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。0 \lt N,V \le 100 ,0 \lt vi,wi,si \le 1000<N,V≤100,0<vi,wi,si≤100
输出格式
输出一个整数,代表最大价值。
样例
输入数据 1
4 10
3 2 2
4 3 2
2 2 1
5 3 4
输出数据 1
8
#include <bits/stdc++.h>
using namespace std;
int v[110],w[110],f[110],s[110];
int main() {
int n,m;
cin>>n>>m;
for(int i = 1;i <= n;i++){
cin>>v[i]>>w[i]>>s[i];
}
//循环i件物品
for(int i = 1; i <= n; i++) {
//每种物品有si件,可以认为有s[i]个物品
for(int k = 1;k <= s[i];k++){
//逆序循环背包容量,转换为01背包
for(int j = m;j >= v[i];j--){
f[j] = max(f[j],f[j-v[i]]+w[i]);
}
}
}
cout<<f[m];
}
多重背包(2)
说明
有N种物品和一个容量是V的背包。
第i种物品最多有si件,每件体积是vi,价值是wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
输出格式
输出一个整数,表示最大价值。
0<N≤1000
0<V≤2000
0<vi,wi,si≤2000
样例
输入数据 1
4 5
1 2 3
2 4 1
3 4 3
4 5 2
输出数据 1
10
#include <bits/stdc++.h>
using namespace std;
//由于要将物品拆分
int f[2020],v[15050],w[15050];
int op = 0;
int main() {
//二进制优化
//7:表示为0~7的和
//7分为:1 1 1 1 1 1 1,将7件物品分为7种物品
//二进制分法:2^2+2^1+2^0
//凑出一个整数Si的时间复杂度:log2(Si)
/*
如果要凑一个整数10
理论上需要log2(10)=4个数
但4个数1 2 4 8,不过会多凑一些数出来
但其实需要的数是: 1 2 4 3就能凑出0~10
也就是说:2^p是<=Si 2^p+1 > Si,求出一个p
这个p就是需要的数的数量
需要的最后一个数 = Si - (2^0+2^1+...+2^p)
*/
int n,m;
cin>>n>>m;
//拆分物品
for(int i = 1;i <= n;i++){
int v1,w1,s;
cin>>v1>>w1>>s;
int k = 1;//k代表2的幂
while(k <= s){
v[++op] = v1 * k;
w[op] = w1 * k;
s -= k;
k *= 2;
}
//如果s还有值,说明s不是正好是2的整数次方
if(s){
v[++op] = v1 * s;
w[op] = w1 * s;
}
}
//转换为01背包
for(int i = 1;i <= op;i++){
for(int j = m;j >= v[i];j--){
f[j] = max(f[j],f[j-v[i]]+w[i]);
}
}
cout<<f[m];
return 0;
}
混合背包
说明
有 N 种物品和一个容量是 V 的背包。
物品一共有三类:
第一类物品只能用1次(01背包);
第二类物品可以用无限次(完全背包);
第三类物品最多只能用 si 次(多重背包);
每种体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
si=−1 表示第 i 种物品只能用1次;
si=0 表示第 i 种物品可以用无限次;
si>0 表示第 i 种物品可以使用 si 次;
输出格式
一个整数,表示最大价值。
样例
输入数据 1
4 5
1 2 -1
2 4 1
3 4 0
4 5 2
输出数据 1
8
数据范围
0<N,V≤1000
0<vi,wi≤1000
−1≤si≤1000
#include <bits/stdc++.h>
using namespace std;
int n,V;
struct kk {
int w,v,m;
};
kk a[1001];
int f[20001];
void completebag(int v,int w) {
for(register int i=v; i<=V; ++i)
f[i]=max(f[i],f[i-v]+w);
return;
}
void zeronebag(int v,int w) {
for(register int i=V; i>=v; --i)
f[i]=max(f[i],f[i-v]+w);
return;
}
void multiplebag(int v,int w,int m) {
if(m*v>V) {
completebag(v,w);
return;
}
int k=1;
while(k<=m) {
zeronebag(v*k,w*k);
m-=k;
k*=2;
}
zeronebag(v*m,w*m);
return;
}
int main() {
scanf("%d%d",&n,&V);
for(register int i=1; i<=n; ++i)
scanf("%d%d%d",&a[i].v,&a[i].w,&a[i].m);
memset(f,0x0,sizeof(f));
for(register int i=1; i<=n; ++i) {
if(a[i].m==-1) zeronebag(a[i].v,a[i].w);
if(a[i].m==0) completebag(a[i].v,a[i].w);
if(a[i].m>0) multiplebag(a[i].v,a[i].w,a[i].m);
}
printf("%d\n",f[V]);
return 0;
}