【ACWing】1024. 装箱问题

题目地址:

https://www.acwing.com/problem/content/1026/

有一个箱子容量为 V V V,同时有 n n n个物品,每个物品有一个体积(正整数)。要求 n n n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

输入格式:
第一行是一个整数 V V V,表示箱子容量。第二行是一个整数 n n n,表示物品数。接下来 n n n行,每行一个正整数(不超过 10000 10000 10000),分别表示这 n n n个物品的各自体积。

输出格式:
一个整数,表示箱子剩余空间。

数据范围:
0 < V ≤ 20000 0<V≤20000 0<V20000
0 < n ≤ 30 0<n≤30 0<n30

这也是个 0 − 1 0-1 01背包问题,但问的是能装的最大体积,本质上我们只需要求一下 [ 0 , 1 , . . . , V ] [0,1,...,V] [0,1,...,V]这些体积是否存在装载方式即可。思路是动态规划,设bool数组 f [ i ] [ j ] f[i][j] f[i][j]是只考虑前 i i i个物品的情况下,能否装恰好 j j j的体积。那么可以按照物品 i i i是否放来分类,有: f [ i ] [ j ] = f [ i − 1 ] [ j ] ∨ f [ i − 1 ] [ j − v i ] f[i][j]=f[i-1][j]\lor f[i-1][j-v_i] f[i][j]=f[i1][j]f[i1][jvi] v i v_i vi是第 i i i个物品的体积。代码如下:

#include <iostream>
using namespace std;

const int N = 20020, M = 31;
int a[M];
bool f[M][N];
int n;

int main() {
    
    
    int V;
    cin >> V >> n;

    for (int i = 1; i <= n; i++) cin >> a[i];

    int res = V;
    f[0][0] = true;
    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= V; j++) {
    
    
            f[i][j] = f[i - 1][j];
            if (j >= a[i]) 
                f[i][j] |= f[i - 1][j - a[i]];
            if (f[i][j]) res = min(res, V - j);
        }

    cout << res << endl;

    return 0;
}

时空复杂度 O ( n V ) O(nV) O(nV)

可以考虑空间优化,每行从右向左更新:

#include <iostream>
using namespace std;

const int N = 20020, M = 31;
int a[M];
bool f[N];
int n;

int main() {
    
    
    int V;
    cin >> V >> n;

    for (int i = 1; i <= n; i++) cin >> a[i];

    int res = V;
    f[0] = true;
    for (int i = 1; i <= n; i++)
        for (int j = V; j >= a[i]; j--) {
    
    
            f[j] |= f[j - a[i]];
            if (f[j]) res = min(res, V - j);
        }

    cout << res << endl;

    return 0;
}

时间复杂度不变,空间 O ( V ) O(V) O(V)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/114248168