一、01背包
问题描述:
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
解答:
状态转移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
即将问题分解为“将前i件物品放入容量为v的背包中”这个子问题,如果不放第i件物品,则f[i][v]=f[i-1][v],如果放这就是f[i-1][v-c[i]]+w[i],选取最大那个;
以上式子可以优化空间度为: f[v]=max{f[v],f[v-cost]+weight},循环顺序为倒序;
有的题目要求“恰好装满背包”时的最优解,那么在初始化时除了f[0]为0其它f[1..V]均设为-∞,这样就可以保证最终得到的f[N]是一种恰好装满背包的最优解;否则初始化为0即可;
二、完全背包问题
问题描述:
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
解答:
状态转移方程:f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]}
优化成一维背包:f[v]=max{f[v],f[v-c[i]]+w[i]},循环顺序为正序
三、多重背包
问题描述:
有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
解答:
状态转移方程:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}
代码如下:
#include<bits\stdc++.h> using namespace std; const int maxn=1e6; int dp[maxn]; int value[maxn],weight[maxn],number[maxn]; int bag; void ZeroOnePack(int weight,int value) { for(int i=bag;i>=weight;i--) { dp[i]=max(dp[i],dp[i-weight]+value); } } void CompletePack(int weight,int value) { for(int i=weight;i<=bag;i++) { dp[i]=max(dp[i],dp[i-weight]+value); } } void MultiplePack(int weight,int value,int number) { if(bag<weight*number) { CompletePack(weight,value); return; } else { int k=1; while(k<=number) { ZeroOnePack(k*weight,k*value); number-=k; k*=2; } ZeroOnePack(number*weight,number*value); } } int main() { int n; while(~scanf("%d%d",&bag,&n)) { int sum=0; for(int i=0;i<n;i++) { scanf("%d",&number[i]); scanf("%d",&weight[i]); scanf("%d",&value[i]); } memset(dp,0,sizeof(dp)); for(int i=0;i<n;i++) { MultiplePack(weight[i],value[i],number[i]); } cout<<dp[bag]<<endl; } }