SCUBADIV - Scuba diver 题解
题目大意
潜水员有 \(n\) 个气缸,每个气缸能够提供容量为 \(o_i\) 的氧气和容量为 \(d_i\) 的氮气,每个气缸的重量为 \(w_i\)。
给出潜水员所需要的氧气量和氮气量,求所需气缸的总重的最低限度是多少。
解题思路
对于每个气缸,有两种不同的费用:氧气和氮气,需要满足这两个条件,才能得到价值,也就是气缸的重量;所以可以看作是二维费用的背包问题。
将每个气缸的质量看做物品,把气缸的总重的最低限度看做背包。
枚举每个气缸,每次做二维费用的背包,如果当前的氧气或氮气超过了所需要的氧气或氮气,可以直接用需求量代替。
二维费用的背包:
划分阶段:
- 以当前的氧气瓶为阶段;
状态表达:
- 设 \(f_{i,j}\) 表示当所需的氧气量为 \(i\),氮气量为 \(j\) 的时候气缸的最小重量;
状态转移:
-
当不选第 \(i\) 个气缸时,不变,\(f_{j,k}=f_{j,k}\);
-
当选第 \(i\) 个气缸时,减去当前的氧气和氮气,加上质量,\(f_{j,k}=f_{j-o_i,k-d_i}+w_i\);
-
这里注意,当 \(j-o_i\) 或 \(k-d_i\) 小于零时,也就是选中当前的氧气和氮气后还有剩余的氧气和氮气,这种情况可以直接用 \(j\) 或 \(k\),所以可以特判一下,如果 \(j-o_i\) 或 \(k-d_i\) 小于零,\(j-o_i\) 或 \(k-d_i\) 等于 \(0\)。
初始状态:
- 因为当所需的氧气量为 \(0\),氮气量为 \(0\) 的时候气缸的最小重量也是 \(0\),所以 \(f_{0,0}=0\);要取最小值,所以其余全部为 \(\inf\);
求解目标:\(f_{n,m}\);
代码
最后输出不加换行会 WA!
#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int INF=0x3f;
int q;
int main() {
cin>>q;
while(q--) {
int n,m,idx;
cin>>n>>m>>idx;
int o[1005],d[1005],w[1005],f[25][80];
for(ri i=1; i<=idx; i++)
cin>>o[i]>>d[i]>>w[i];
memset(f,INF,sizeof(f));
f[0][0]=0;//初始状态
for(ri i=1; i<=idx; i++)//阶段
for(ri j=n; j>=0; j--)//氧气
for(ri k=m; k>=0; k--) {//氮气
int x=j-o[i],y=k-d[i];
if(x<0)x=0;
if(y<0)y=0;
f[j][k]=min(f[j][k],f[x][y]+w[i]);
}
cout<<f[n][m]<<'\n';//求解目标
}
return 0;
}