ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

潜水员

2022-07-23 23:34:15  阅读:235  来源: 互联网

标签:right 气缸 容量 int leq 潜水员


潜水员

潜水员为了潜水要使用特殊的装备。

他有一个带 $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 \leq m \leq 21$,
$1 \leq n \leq 79$,
$1 \leq k \leq 1000$,
$1 \leq a_i \leq 21$,
$1 \leq b_i \leq 79$,
$1 \leq c_i \leq800$

输入样例:

5 60
5
3 36 120
10 25 129
5 50 250
1 45 130
4 20 119

输出样例:

249

 

解题思路

  这是一个二维费用的背包问题。与之前的背包问题不同的是,这里要求费用$1$至少是多少,费用$2$至少是多少。

  下面先给出一种状态表示,但根据这种状态表示来进行计算会超时。

  $f \left( {i, j, k} \right)$表示从前$i$个物品中选,氧气的容量恰好为$j$,氮气的容量恰好为$k$的所有方案的集合,属性是重量的最小值。状态转移方程为$$f \left( {i, j, k} \right) = min \{ f \left( {i - 1, j, k} \right),~ f \left( {i - 1, j - v_{1i}, k - v_{2i}} \right) + w_i \}$$

  其中$j$和$k$的最大上限均为$21 \times 79$,这是因为可能会有极端的数据,比如输入的氧气和氮气的容量全是“$1~79$”或者“$21~1$”。因此计算量就是$1000 \times \left( {21 \times 79} \right)^{2}$,必然会超时,所以需要换一种状态表示。

  状态表示还是$f \left( {i, j, k} \right)$,不过集合的含义变了,表示从前$i$个物品中选,氧气的容量至少为$j$,氮气的容量至少为$k$的所有方案的集合,属性是重量的最小值。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 30, M = 90;
 5 
 6 int f[N][M];
 7 
 8 int main() {
 9     int n, m1, m2;
10     scanf("%d %d %d", &m1, &m2, &n);
11     
12     memset(f, 0x3f, sizeof(f));
13     f[0][0] = 0;    // 一开始从前0个物品中选,也就是没有,氧气氮气的容量均为0,其他的状态俊不合法
14     for (int i = 1; i <= n; i++) {
15         int v1, v2, w;
16         scanf("%d %d %d", &v1, &v2, &w);
17         for (int j = m1; j >= 0; j--) {
18             for (int k = m2; k >= 0; k--) { // j和k均循环到0,即使k-v1<0或k-v2<0也是合法的
19                 // 得到负数时说明只选择第i个物品就可以达到最小量j或k,意味着之前没有选含这个气体的物品,因此可以取0
20                 f[j][k] = min(f[j][k], f[max(0, j - v1)][max(0, k - v2)] + w);
21             }
22         }
23     }
24     
25     printf("%d", f[m1][m2]);
26     
27     return 0;
28 }

   代码中取$max$的原因是,每个物品装有的气体的容量都大于等于$1$,因此当某个气体减去当前瓶子的气体容量后小于$0$,是等价于$0$的,因为当容量小于$0$意味着一个瓶子都没有选,而每个瓶子的装有气体的容量大于等于$1$。

 

参考资料 

  AcWing 1020. 潜水员(算法提高课):https://www.acwing.com/video/379/

标签:right,气缸,容量,int,leq,潜水员
来源: https://www.cnblogs.com/onlyblues/p/16513532.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有