1.火车运输

前置知识点:动态规划

1.问题描述

钢厂有一辆用于运送废旧钢材的火车,它具有两节车厢,其中车厢 1 1 1 的最大载重量为 A A A,车厢 2 2 2 的最大载重量为 B B B。现在一共有 N N N 件废旧钢材需要被运输,其中第 i i i 件钢材的重量为 w i w_i wi​。为了最大化运输效率,车长想要一次性运输走重量尽可能多的钢材,请你帮助车长计算出一次运输最多可以带走多大重量的钢材。

每件钢材都是独立的不可分割的,只能被放置在某一节车厢中。在装载钢材时只需要考虑重量条件即可。

2. 输入格式

输入的第一行包含三个整数 N N N, A A A, B B B,用一个空格分隔,分别表示钢材的数目以及两节车厢的最大载重。

第二行包含 N N N 个整数,分别表示 w 1 w_1 w1​, w 2 w_2 w2​, …, w n w_n wn​,相邻两个整数之间使用一个空格分隔。

3. 输出格式

输出一个整数表示答案。

4. 样例输入

3 10 8
8 9 1

5. 样例输出

18

6. 样例说明

车厢 1 1 1 装入第 2 2 2 件和第 3 3 3 件钢材,车厢 2 2 2 装入第 1 1 1 件钢材。

7. 评测用例规模与约定

对于 30 % 30\% 30% 的评测用例, 1 ≤ N ≤ 10 1 ≤ N ≤ 10 1≤N≤10;

对于所有评测用例, 1 ≤ N ≤ 200 1 ≤ N ≤ 200 1≤N≤200, 1 ≤ w i , A , B ≤ 1 , 000 1 ≤ w_i, A, B ≤ 1,000 1≤wi​,A,B≤1,000。

8. 原题链接

火车运输

2. 解题思路

这道题目没有直观的解决方案,但我们注意到 n , A , B n, A, B n,A,B 的值域都相对较小,因此可以考虑使用动态规划来解决。

首先,我们需要定义状态。令 f i , j , k f_{i,j,k} fi,j,k​ 表示只考虑前 i i i 件钢材,使得第一个车厢的载重量严格为 j j j,同时第二个车厢的载重量严格为 k k k 的情况。

这个状态设计必须能够导出最终的答案。因此,我们可以分别遍历所有可能的 j j j(满足 j ∈ [ 1 , A ] j \in[1,A] j∈[1,A])和 k k k(满足 k ∈ [ 1 , B ] k\in[1,B] k∈[1,B])。如果 f n , j , k f_{n,j,k} fn,j,k​ 为真,那么 j + k j+k j+k 就是一个可行的答案。最终的答案即为所有可能的 ( j , k ) (j,k) (j,k) 组合中, j + k j+k j+k 的最大值。

接下来,我们需要初始化状态。在最初,没有任何钢材被放入任何一个车厢,所以我们设定 f 0 , 0 , 0 f_{0,0,0} f0,0,0​ 为真。

然后,我们来考虑状态转移。对于 f i , j , k f_{i,j,k} fi,j,k​,当考虑第 i i i 个钢材时,我们有三种选择:

  • 将其放入车厢 A A A(要求 j ≥ a i j \ge a_i j≥ai​),此时的状态转移方程为:
    f i , j , k = f i , j , k ∣ f i − 1 , j − a i , k f_{i,j,k}=f_{i,j,k} \mid f_{i-1,j-a_i,k} fi,j,k​=fi,j,k​∣fi−1,j−ai​,k​

  • 将其放入车厢 B B B(要求 k ≥ a i k \ge a_i k≥ai​),此时的状态转移方程为:
    f i , j , k = f i , j , k ∣ f i − 1 , j , k − a i f_{i,j,k}=f_{i,j,k} \mid f_{i-1,j,k-a_i} fi,j,k​=fi,j,k​∣fi−1,j,k−ai​​

  • 不放入任何车厢。

在实现过程中,我们会发现,按照这样的状态设计会导致空间消耗过大。因此,我们可以借鉴 01 01 01 背包问题中的滚动数组思想,优化掉第一个维度,并在枚举 j , k j,k j,k 时进行反向枚举。

时间复杂度为: O ( n A B ) O(nAB) O(nAB)。

3. AC_Code

  • C++
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;

int n, A, B;
bool f[N][N];
int main()
{
    cin >> n >> A >> B;

    vector<int> a(n);
    for (int i = 0; i < n; ++i)
    {
        cin >> a[i];
    }

    f[0][0] = true;
    for (int i = 0; i < n; ++i)
    {
        for (int j = A; j >= 0; j--)
        {
            for (int k = B; k >= 0; k--)
            {
                if (j >= a[i])
                    f[j][k] |= f[j - a[i]][k];
                if (k >= a[i])
                    f[j][k] |= f[j][k - a[i]];
            }
        }
    }
    int ans = 0;
    for (int j = A; j >= 0; j--)
    {
        for (int k = B; k >= 0; k--)
        {
            if (f[j][k])
                ans = max(ans, j + k);
        }
    }

    cout << ans << '\n';
}

  • Java
import java.util.*;

public class Main {
    static final int N = 1010;
    static boolean[][] f = new boolean[N][N];

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int A = sc.nextInt();
        int B = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = sc.nextInt();
        }

        f[0][0] = true;
        for (int i = 0; i < n; i++) {
            for (int j = A; j >= 0; j--) {
                for (int k = B; k >= 0; k--) {
                    if (j >= a[i])
                        f[j][k] = f[j][k] || f[j - a[i]][k];
                    if (k >= a[i])
                        f[j][k] = f[j][k] || f[j][k - a[i]];
                }
            }
        }

        int ans = 0;
        for (int j = A; j >= 0; j--) {
            for (int k = B; k >= 0; k--) {
                if (f[j][k])
                    ans = Math.max(ans, j + k);
            }
        }

        System.out.println(ans);
    }
}
  • Python
N = 1010
f = [[False]*N for _ in range(N)]

n, A, B = map(int, input().split())
a = list(map(int, input().split()))

f[0][0] = True
for i in range(n):
    for j in range(A, -1, -1):
        for k in range(B, -1, -1):
            if j >= a[i]:
                f[j][k] = f[j][k] or f[j - a[i]][k]
            if k >= a[i]:
                f[j][k] = f[j][k] or f[j][k - a[i]]

ans = 0
for j in range(A, -1, -1):
    for k in range(B, -1, -1):
        if f[j][k]:
            ans = max(ans, j + k)

print(ans)

更多推荐