二维费用的背包问题(潜水员)

感觉大多数人都没有讲清楚 ,我尝试看看,能不能用我笨拙的语言解释清楚,从而让更多人能够理解

题目

潜水员为了潜水要带足够的氧气和氮气。他有若干个带两种气体的气缸:氧气和氮气。每个气缸都有各自的重量和两种的气体含量。潜水员为了完成他的工作需要一定数量的氧气和氮气。问他完成工作所需气缸的总重的最小重量的是多少?
输入
第一行有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) 1ai211bi791ci800 三个整数整数。分别为第 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 iv1或者 j − v − 2 j-v-2 jv2小于 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;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值