1020. 潜水员
题目链接
1020. 潜水员
潜水员为了潜水要使用特殊的装备。
他有一个带2种气体的气缸:一个为氧气,一个为氮气。
让潜水员下潜的深度需要各种数量的氧和氮。
潜水员有一定数量的气缸。
每个气缸都有重量和气体容量。
潜水员为了完成他的工作需要特定数量的氧和氮。
他完成工作所需气缸的总重的最低限度的是多少?
例如:潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
如果潜水员需要5升的氧和60升的氮则总重最小为\(249\)(\(1,2\)或者\(4,5\)号气缸)。
你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。
输入格式
第一行有2个整数 \(m,n\)。它们表示氧,氮各自需要的量。
第二行为整数 \(k\) 表示气缸的个数。
此后的 \(k\) 行,每行包括\(a_i,b_i,c_i\),\(3\)个整数。这些各自是:第 \(i\) 个气缸里的氧和氮的容量及气缸重量。
输出格式
仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。
数据范围
\(1≤m≤21,\)
\(1≤n≤79,\)
\(1≤k≤1000,\)
\(1≤a_i≤21,\)
\(1≤b_i≤79,\)
\(1≤c_i≤800\)
输入样例:
5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119
输出样例:
249
解题思路
二维费用背包变形
-
状态表示:\(f[i][j][t]\) 表示前 \(i\) 个物品,体积至少为 \(j\),重量至少为 \(t\) 的最小价值
-
状态计算:\(f[i][j][t]=min(f[i][j][t],f[i-1][max(0,j-a)][max(0,t-b)]+c)\)
分析:关键在于 \(j-a\) 或 \(t-b\) 为负数的情况,以 \(j\) 为例:由于这样的状态在 \(j-a\sim 0\) 是非法的,应该直接考虑至少为 \(0\) 的情况,即负数的情况是合法的,对于 \(j\) 要循环到 \(0\)
- 时间复杂度:\(O(nmk)\)
代码
// Problem: 潜水员
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1022/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair PII;
typedef pair PLL;
template bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int m,n,k,f[25][80];
int main()
{
cin>>m>>n>>k;
memset(f,0x3f,sizeof f);
f[0][0]=0;
for(int i=1;i<=k;i++)
{
int a,b,c;
cin>>a>>b>>c;
for(int j=m;~j;j--)
for(int t=n;~t;t--)f[j][t]=min(f[j][t],f[max(0,j-a)][max(0,t-b)]+c);
}
cout<