SP181 SCUBADIV - Scuba diver 题解

发布时间 2023-04-02 08:45:59作者: Ggsddu_zzy

题目传送门

题目大意

潜水员有 \(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!

AC 记录

#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];//求解目标
	}
	return 0;
}