装箱问题

题目描述

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

输入格式

1个整数,表示箱子容量

1个整数,表示有n个物品

接下来n行,分别表示这n个物品的各自体积

输出格式

1个整数,表示箱子剩余空间。

思路

这个是一个基础的01背包问题,时间复杂度是O(nm),空间复杂度初始为O(nm),其主要实现思路是\(F[i,m] = max(F[i-1,m], F[i-1,m-C\)\(_i\)]+W\(_i\)),其中i标识当前物品,m标识剩余空间,\(C_i\quad\)表示当前物品所消耗的空间,\(W_i\quad\)表示当前物品所具有的价值,每次计算\(F[i,m]\)时都只与上一次放入物品后的状态有关,那么我们就考虑将空间复杂度优化为O(m),并且将遍历顺序改为\(\quad v : V->C_i\quad\),每次从最大空间出发,直到当前物品所需空间为止,如果是\(\quad v: C_i -> V \quad\),当前放入的物品的记录也会参与运算中去了,就与需求不符。\(F[v]\)表示的是当空间为v的情况下可以具有的最大价值。

#include <stdio.h>

#define max(a,b) ((a)>(b)?(a):(b))

int item[32]={0};//物品体积
int f[20002]={0};
int V;


void ZeroOnePack(int *F,int c,int w){
    for(int v=V;v>=c;v--){
        F[v]=max(F[v],F[v-c]+w);
    }
}

int main(){
    int n;
    scanf("%d%d",&V,&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&item[i]);
    }
    //如果将物品体积从小到大排序呢?
    for(int i=1;i<=n;i++){
        ZeroOnePack(f,item[i],item[i]);
    }

    printf("%d\n",V-f[V]);

}

参考资料

《背包九讲》,说的真的很好。

posted @ 2021-10-29 09:39  hertz-01  阅读(48)  评论(0)    收藏  举报