You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##AcWing 1020. 潜水员

一、题目描述

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

他有一个带2种气体的气缸:一个为氧气,一个为氮气。

让潜水员下潜的深度需要各种数量的氧和氮。

潜水员有一定数量的气缸。

每个气缸都有重量和气体容量。

潜水员为了完成他的工作需要特定数量的氧和氮。

他完成工作所需气缸的总重的 最低限度 的是多少?

例如:潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:

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

如果潜水员需要5升的氧和60升的氮则总重最小为24912或者45号气缸)。

你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的 最低值

输入格式 第一行有2个整数 mn。它们表示氧,氮各自需要的量。

第二行为整数 k 表示气缸的个数。

此后的 k 行,每行包括a_ib_ic_i3个整数。这些各自是:第 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,k) 表示从前i个物品中选,且花费1不超过j,花费2不超过k最大 价值

  • 潜水员 f(i,j,k) 表示从前i个物品中选,且花费1不少于j,花费2不少于k最小 价值

本题是一个 二维费用01背包问题 ,但和一般的 二维费用01背包问题 不同

这题要求的是 费用不少于 规定条件,因此我们需要对于 状态的定义 进行改变

闫氏DP分析法

这样分析完,似乎与普通的二维费用背包没有区别!这肯定是不可能的,我们必然是遗漏了些什么!!

考虑j-v_1<0,k-v_2<0的情况!

有普通的二维费用背包问题中,j,k是不能进行超载的,超过了背包就太重, 背包就 了!

在本题中是 可以超载 的,理解一下超载是什么意思:

  • j:氧气还需要j
  • k:氮气还需要k

举栗子j=2,k=5,就是氧气还需要2升,氮气还需要5升,现在出现的某个气瓶,氧气20升,氮气50升,一个就可以把你的需求满足,那么请问:你还需要氧气多少升、氮气多少升呢?

:不需要,都可以满足要求了,即j=0,k=0,也就是f[i-1][0][0]+w,而对于一个无欲无求的f[i-1][0][0]自然是等于0,也就是f[i][j][k]=w

三、三维解法

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
const int M = 110;
int n, m, m1, m2;
int f[N][M][M];

int main() {
    cin >> m1 >> m2 >> n;
    memset(f, 0x3f, sizeof f);
    f[0][0][0] = 0;

    for (int i = 1; i <= n; i++) {
        int v1, v2, w;
        cin >> v1 >> v2 >> w;
        for (int j = 0; j <= m1; j++)
            for (int k = 0; k <= m2; k++) {
                f[i][j][k] = f[i - 1][j][k];
                f[i][j][k] = min(f[i - 1][j][k], f[i - 1][max(0, j - v1)][max(0, k - v2)] + w);
            }
    }
    cout << f[n][m1][m2] << endl;
    return 0;
}

四、二维解法

#include <bits/stdc++.h>
using namespace std;

const int N = 22, M = 80;

int n, m, K;
int f[N][M];

int main() {
    cin >> n >> m >> K;

    memset(f, 0x3f, sizeof f);
    f[0][0] = 0;

    while (K--) {
        int v1, v2, w;
        cin >> v1 >> v2 >> w;
        for (int i = n; i >= 0; i--)
            for (int j = m; j >= 0; j--)
                f[i][j] = min(f[i][j], f[max(0, i - v1)][max(0, j - v2)] + w);
    }

    cout << f[n][m] << endl;

    return 0;
}