背包问题(Knapsack problem)是一种组合优化的NP完全问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。相似问题经常出现在商业、组合数学,计算复杂性理论、密码学和应用数学等领域中。也可以将背包问题描述为决定性问题,即在总重量不超过W的前提下,总价值是否能达到V?它是在1978年由Merkle和Hellman提出的。
01背包
问题描述:
给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
算法分析:
二维做法
用一个数组f[i][j]表示,在只有i个物品,容量为j的情况下背包问题的最优解,那么当物品种类变大为i+1时,最优解是什么?第i+1个物品可以选择放进背包或者不放进背包(这也就是0和1),假设放进背包(前提是放得下),那么f[i+1][j]=f[i][j-w[i+1]+v[i+1];如果不放进背包,那么f[i+1][j]=f[i][j]。
这就得出了状态转移方程:
f[i+1][j]=max(f[i][j],f[i][j-w[i+1]+v[i+1])。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=2e2+10;
int f[40][N],w[40],v[40],n,C;
int main()
{
//fre();
scanf("%d%d",&C,&n);
for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]);
for(int i=1;i<=n;i++)
for(int j=C;j>0;j--)
{
if(w[i]<=j) f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]);
else f[i][j]=f[i-1][j];
}
printf("%d",f[n][C]);
return 0;
}
一维做法:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=2e2+10;
int f[N],w[40],v[40],n,C;
int main()
{
//fre();
scanf("%d%d",&C,&n);
for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&v[i]);
for(int i=1;i<=n;i++)
for(int j=C;j>=w[i];j--)
if(w[i]<=j) f[j]=max(f[j],f[j-w[i]]+v[i]);
printf("%d",f[C]);
return 0;
}
其他背包问题:
背包问题(2)-完全背包