原题链接:acwing1020. 潜水员
这是一个二维费用的背包问题,背包容量有下界限制(氧、氮),求背包能装的最小价值(气缸重量)
状态表示与状态转移如上图所示
f[i][j][k]表示考虑前i个物品,其氧气含量>=j,氮气含量>=k的最小价值
f[i][j][k]由可以两种状态转移而来:
当不选第i个物品时,f[i][j][k]=f[i-1][j][k],v1 v2为第i个物品的氧、氮含量
当选第i个物品时, f[i][j][k]=f[i-1][j-v1][k-v2]+w
需要注意的是,当选第i个物品时,j<v1和k<v2的情况也是合法的,
当j<v1时j==v1
当k<v2时k==v2
背包问题考虑选的物品与体积关系时的初始化:
背包问题一共有三种物品与总体积的关系:最多、恰好、至少
1.体积最多为j,f[i]=0,v>=0,
从实际意义出发,当总体积为j时,f[0][j]表示一件物品都不选的最大价值,此时的价值为0
2.体积恰好是j,f[0]=0,f[i]=+(-)inf,v>=0,
体积恰好为j时,f[0][0]=0表示一件物品都不选,体积恰好为0的价值,因此f[0][0]=0,
f[0][j>0]表示一件物品都不选体积恰好为j>0时的最大(小价值),这种情况是不存在的,f[0][j]=+(-)inf(具体问题具体分析)
3.体积大于等于j,f[i]=0,f[i]=+(-)inf ,和上个体积恰好为j的分析类似,
不一样的情况是体积恰好为j那么所选物品的总体积只能是j,体积至少是j时,物品总体积可以超过j这时候也是合法的,需要考虑边际情况,也就是j-v<0也是合法的
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=22,M=80;
int f[N][M];
int main(){
int n,m,k;
cin>>n>>m>>k;
memset(f,0x3f,sizeof f);
f[0][0]=0;
while(k--){
int v1,v2,w;
scanf("%d%d%d",&v1,&v2,&w);
for(int i=n;i>=0;i--)
for(int j=m;j>=0;j--){
if(i<v1||j<v2) f[i][j]=min(f[i][j],f[max(i-v1,0)][max(j-v2,0)]+w);
else f[i][j]=min(f[i][j],f[i-v1][j-v2]+w);
}
}
cout<<f[n][m]<<endl;
return 0;
}