【刷题】动态规划——背包问题:潜水员【二维费用、限制为不少于、求价值最小值】

在这里插入图片描述题目链接
氧气氮气对应二维费用背包问题的体积和重量,气缸重量对应价值。
问题则是求体积和重量至少为m和n时,价值和最小。

f[i][j][k]表示前i个物品,体积至少是j,重量至少是k的价值和最小。因此答案就是f[k][m][n]

可以分成两种,选第i个物品和不选第i个物品
1、不选第i个物品:f[i][j][k] = f[i-1][j][k]
2、选第i个物品:f[i-1][j - v[i]][k - m[i]] + w[i]

由于条件由经典背包问题的“不超过”,变成了“至少是”,所以和原来的问题主要有两点不同(下面用f[i][j]表示前i个物品j容量):

1、初始化不同。
初始化只需看i=0(一个都不选)的情况,i>0可由i=0递推而来。
“不超过” 的初始化要将f[0][j]全部设为0,是因为体积不超过j,包括了体积为0的选法
“恰好是” 的初始化只有f[0][0]=0,其余都是无穷,因为一个都不选体积只能是0,不能是其他值。
“至少是” 的初始化只有f[0][0]=0,其余都是无穷。因为一个都不选体积只能是0,所以只有体积至少是0才是合法的。

2、j的循环范围不同
不超过和恰好是的情况下,j - v[i] < 0是无意义的,体积不超过-1和恰好是-1都是不可能的选法,因为体积最小就是0。
”至少是“的情况下,j - v[i] < 0的时候仍然可以进行状态转移,因为体积至少是-1、-2、-3也是有意义的,它包括了体积>=0的选法。可将负数的部分答案记在f[i][0]

体积条件写法
不超过f全初始化为0;循环时保证j-v[i]>=0
恰好是f[0]=0,其余无穷;循环时保证j-v[i]>=0
至少是f[0]=0,其余无穷;循环时不必保证j-v[i]>=0

ps.初始化取正无穷还是负无穷取决于问题求最大值还是最小值,求最大取负无穷,求最小取正无穷。

#include <iostream>
#include <cstring>
using namespace std;
int m, n, k, f[22][80];
int a[1005], b[1005], c[1005];
int main() {
	scanf("%d%d%d", &m, &n, &k);
	
	for (int i = 1; i <= k; i++) {
		scanf("%d%d%d", &a[i], &b[i], &c[i]);
	}
	
	memset(f, 0x3f, sizeof(f));
	f[0][0] = 0;
	for (int i = 1; i <= k; i++) {
		for (int j = m; j >= 0; j--) {
			for (int kk = n; kk >= 0; kk--)  {
				f[j][kk] = min(f[j][kk], f[max(j - a[i], 0)][max(kk - b[i], 0)] + c[i]);
			}
		}
	}
	printf("%d\n", f[m][n]);
}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值