感觉大多数人都没有讲清楚 ,我尝试看看,能不能用我笨拙的语言解释清楚,从而让更多人能够理解
题目
潜水员为了潜水要带足够的氧气和氮气。他有若干个带两种气体的气缸:氧气和氮气。每个气缸都有各自的重量和两种的气体含量。潜水员为了完成他的工作需要一定数量的氧气和氮气。问他完成工作所需气缸的总重的最小重量的是多少?
输入
第一行有2整数m,n(1≤m≤21,1≤n≤79)。它们表示氧,氮各自需要的量。
第二行为整数k(1≤n≤1000)表示气缸的个数。
此后的k行,每行包括
a
i
a_i
ai,
b
i
b_i
bi,
c
i
c_i
ci
(
1
≤
a
i
≤
21
,
1
≤
b
i
≤
79
,
1
≤
c
i
≤
800
)
(1≤ai≤21,1≤bi≤79,1≤ci≤800)
(1≤ai≤21,1≤bi≤79,1≤ci≤800) 三个整数整数。分别为第
i
i
i个气缸里的氧和氮的含量及气缸的重量。
输出
输出一个整数,为潜水员完成工作所需的气缸的重量总和的最小重量。
思路
这题题意说明我们只需要我们只需要让所选的气缸中的氧气和氮气总含量不小于工作所需就可以符合要求,然后再在所有符合要求的方案中找出最小值就可以。
我们可以开一个数组
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]:表示从前
i
i
i个气缸中选,氧气体积不小于
j
j
j,氮气体积不小于
k
k
k的所有方案中的最小重量。
由于本质是01背包,所以我们可以优化成二维,具体缘由不再赘述。
状态转移方程为:
f[i][j]=min(f[i][j],f[max(0,j-v1)][max(0,k-v2)]+w);
这个状态转移方程的含义是不取当前这个气缸和取当前气缸的两种状况取较小值。
在之间取max的缘由是因为如果
i
−
v
1
i-v_1
i−v1或者
j
−
v
−
2
j-v-2
j−v−2小于
0
0
0的话,也是存在这种方案的,也就是什么气缸都不用取,重量为
0
0
0。但是我们为了不越界,所以将小于
0
0
0等价为
0
0
0,因为当氮气和氧气的需求为0时,也是不用取气缸,重量为
0
0
0。
由于这个动态规划数组与一般的背包不同,所以如果初始化也是一个很重要的地方。
我们要将
f
f
f数组初始化为正无穷,这样避免了最后判断最小值的时候还要特判。然后将
f
[
0
]
[
0
]
f[0][0]
f[0][0]单独设置为0。
具体代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=22,M=80;
int n,m,t;
int f[N][M];
int main()
{
cin>>n>>m>>t;
memset(f,0x3f,sizeof f);
f[0][0]=0;
while(t--)
{
int v1,v2,w;
cin>>v1>>v2>>w;
for(int j=n;j>=0;j--)
{
for(int k=m;k>=0;k--)
{
f[j][k]=min(f[j][k],f[max(0,j-v1)][max(0,k-v2)]+w);
}
}
}
cout<<f[n][m]<<endl;
return 0;
}