首页 > 试题广场 >

装箱问题

[编程题]装箱问题
  • 热度指数:6685 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
有一个箱子容量为V(正整数,0 ≤ V ≤ 20000),同时有n个物品(0<n ≤ 30),每个物品有一个体积(正整数)。
要求n个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

输入描述:
1个整数,表示箱子容量
1个整数,表示有n个物品
接下来n行,分别表示这n个物品的各自体积


输出描述:
1个整数,表示箱子剩余空间。
示例1

输入

24
6
8
3
12
7
9
7

输出

0
01背包+空间压缩
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() {

    int V,n;
    cin>>V>>n;
    vector<int> dp(V+1,0);
    vector<int> v(n);
    for(int i=0; i<n; i++){
        cin>>v[i];
    }
    
    for(int i=1; i<=n; i++){
        for(int j=V; j>0; j--){
            if(v[i-1]<=j){
                dp[j] = max(dp[j], dp[j-v[i-1]]+v[i-1]);
            }
        }
    }
    cout<<V-dp[V];
    return 0;
}


发表于 2023-12-27 17:35:41 回复(0)
    /**
     *  背包问题/装箱问题           【动态规划DP】
     *  【原问题】f(n,V):有n个物品(有各自的体积和价值),一个容量为V的背包,最大装入价值(最大装入体积)是多少?
     *
     *  【算法一】:动态规划DP/自底向上     //本题适合【算法一】,因为【子问题之间:可能存在重叠/重复计算】。
     *  【算法二】:降维递归/自顶向下
     *  【降维】:
     *      1.【降维思路】【2种降维思路之一】:直接对原问题/输入数据/数组 进行降维处理;
     *      2.【降维处理】去掉第n个物品(最后一个物品)进行降维。子问题:前n-1个物品对应的多个子问题。
     *      3.【降维关系分析/父子问题关系分析】:
     *          a. 去掉的第n个物品,其体积itemVolumes[n-1]>容量V,即无法装入容器/背包,则【降维关系】为:
     *              f(n,V) = f(n-1,V)
     *          b. 去掉的第n个物品,其体积itemVolumes[n-1]<=容量V,即能够装入容器/背包;
     *             此时有2种选择方案:选择装入该物品、选择不装入该物品;
     *             由于2种方案都有可能产生“全局最优解”,所以需要比较2种方案的解,以得到最优解。
     *             此时,【降维关系】为:
     *              f(n,V) = max{f(n-1,V-itemVolumes[n-1])+itemValues[n-1], f(n-1,V)}
     *          c. 可以发现父问题f(n,V),依赖2个子问题:
     *             前n-1个物品对应的2个子问题:f(n-1,V)、f(n-1,V-itemVolumes[n-1])。
     *             【子问题之间:可能存在重叠/重复计算】:
     *                  例如当第n和n-1物品体积都为3时,上2个子问题都依赖f(n-2,V-3)。
     *          d. 发现“原问题/子问题”由“n和V”2个参数共同定义,所以子问题的个数将是 n*V 个。
     *             所以:如果要暂存子问题的解,应该使用二维数组/矩阵:dp[n][V](不加额外行列时)。
     *            
     *  【降维关系/计算规则/状态转移方程】:
     *      1. 第n个物品,其体积itemVolumes[n-1]>容量V,即无法装入容器/背包,则【降维关系】为:
     *          f(n,V) = f(n-1,V)
     *      2. 第n个物品,其体积itemVolumes[n-1]<=容量V,即能够装入容器/背包,则【降维关系】为:
     *          f(n,V) = max{f(n-1,V-itemVolumes[n-1])+itemValues[n-1], f(n-1,V)}
     *
     *  【动态规划DP算法】中间结果集/二维矩阵dp[n+1][V+1](加额外行列时):
     *      1. dp[i][j]:保存子问题f(i,j)的解,即:
     *                  前i个物品装入容量为j的容器/背包时,最大装入价值/最大装入体积/最大装入个数。
     *         (dp[i][j]:前i个物体放在V中的最大价值/体积是多少。)
     *
     *
     *  @param volume       容器容量/背包体积/箱子体积  v
     *  @param n            物品个数
     *  @param itemVolumes  物品体积
     *  @param itemValues   物品价值(物品价值/物品体积/数量1)
     *  @return             最大装入价值(最大装入体积/最大装入个数)
     */
    public static int maxXBackPackAlgo(int volumeint nint[] itemVolumesint[] itemValues) {

        //x1. 定义:中间结果集/二维矩阵dp[n+1][V+1](加额外行列时):
        int V=volume;
        int[][] dp = new int[n+1][V+1];

        //x2. 计算:中间结果集/二维矩阵dp
        //dp[i][j]:保存子问题f(i,j)的解,即:前i个物品装入容量为j的容器/背包时,最大装入价值
        for(int i=0;i<=n;i++){
            for(int j=0;j<=V;j++){
                //x21. 额外行列初始化
                if(i==0 || j==0){
                    dp[i][j] = 0;
                    continue;
                }
                //x22. 边界计算/无法继续降维问题直接计算
                //无
                //x23. 统一降维计算:
                //【降维关系/计算规则/状态转移方程】:见前面。
                else{
                    if(itemVolumes[i-1] > j) {
                        dp[i][j] = dp[i-1][j];
                    }
                    else {
                        dp[i][j] = Math.max(dp[i-1][j-itemVolumes[i-1]] + itemValues[i-1] , dp[i-1][j]);
                    }
                }
            }
        }

        //x3. 返回结果:最大装入价值(最大装入体积/最大装入个数)
        return dp[n][V];
    }

   
    /**
     *  背包问题/装箱问题(恰好装满时最大装入价值)           【动态规划DP】
     *  【原问题】f(n,V):有n个物品(有各自的体积和价值),一个容量为V的背包,恰好装满时,最大装入价值(最大装入体积)是多少?
     *
     *  【算法一】:动态规划DP/自底向上     //本题适合【算法一】,因为【子问题之间:可能存在重叠/重复计算】。
     *      【与正常背包问题的区别】:见下面,共2处。
     *
     *  【降维关系/计算规则/状态转移方程】:
     *      1. 第n个物品,其体积itemVolumes[n-1]>容量V,即无法装入容器/背包,则【降维关系】为:
     *          f(n,V) = f(n-1,V)
     *      2. 第n个物品,其体积itemVolumes[n-1]<=容量V,即能够装入容器/背包,则【降维关系】为:
     *          f(n,V) = max{f(n-1,V-itemVolumes[n-1])+itemValues[n-1], f(n-1,V)}
     *         【与正常背包问题的区别】:子问题无解时,依赖子问题的方案/父问题 也无解。
     *
     *  【动态规划DP算法】中间结果集/二维矩阵dp[n+1][V+1](加额外行列时):
     *      1. dp[i][j]:保存子问题f(i,j)的解,即:
     *                 前i个物品装入容量为j的容器/背包时,恰好装满时,最大装入价值/最大装入体积/最大装入个数。
     *         【与正常背包问题的区别】:当无解时,即不能完全装满时,取值-1。注意额外行列初始化,区分是否装满。
     *
     *
     *  @param volume       容器容量/背包体积/箱子体积  v
     *  @param n            物品个数
     *  @param itemVolumes  物品体积
     *  @param itemValues   物品价值(物品价值/物品体积/数量1)
     *  @return             最大装入价值(最大装入体积/最大装入个数);无解时,返回-1
     */
    public static int maxXFullBackPackAlgo(int volumeint nint[] itemVolumesint[] itemValues) {

        //x1. 定义:中间结果集/二维矩阵dp[n+1][V+1](加额外行列时):
        int V=volume;
        int[][] dp = new int[n+1][V+1];

        //x2. 计算:中间结果集/二维矩阵dp
        //dp[i][j]:保存子问题f(i,j)的解,即:前i个物品装入容量为j的容器/背包时,恰好装满时,最大装入价值
        //【与正常背包问题的区别】:当无解时,即不能完全装满时,取值-1。注意额外行列初始化,区分是否装满。
        for(int i=0;i<=n;i++){
            for(int j=0;j<=V;j++){
                //x21. 额外行列初始化
                //注意额外行列初始化,区分是否装满。
                if(j==0){           //第一列:都是 恰好装满。
                    dp[i][j] = 0;
                    continue;
                }
                else if(i==0 && j!=0){  //第一行(除第一个外):都是无解, 不能完全装满,取值-1。
                    dp[i][j] = -1;
                    continue;
                }
                //x22. 边界计算/无法继续降维问题直接计算
                //无
                //x23. 统一降维计算:
                //【降维关系/计算规则/状态转移方程】:见前面。
                else{
                    if(itemVolumes[i-1] > j) {
                        dp[i][j] = dp[i-1][j];
                    }
                    else {
                        //【与正常背包问题的区别】:子问题无解时,依赖子问题的方案/父问题 也无解。
                        if(dp[i-1][j-itemVolumes[i-1]] != -1) {
                            dp[i][j] = Math.max(dp[i-1][j-itemVolumes[i-1]] + itemValues[i-1] , dp[i-1][j]);
                        } else {
                            dp[i][j] = dp[i-1][j];
                        }
                    }
                }
            }
        }

        //x3. 返回结果:恰好装满时,最大装入价值(最大装入体积/最大装入个数)
        return dp[n][V];
    }
发表于 2025-03-10 10:41:51 回复(0)
#include <stdio.h>
#include <string.h>
int max(int a,int b){
    return (a>b?a:b);
}
int main() {
    int v, n;
    scanf("%d %d", &v, &n);
    int w[n+1];
    w[0]=0;
    int dp[n+1][v+1];
    memset(dp, 0, sizeof(dp));
    for (int i=1; i<=n; i++) {
        scanf("%d",&w[i]);
    }
    for (int i=1; i<=n; i++) {
         for (int j=1; j<=v; j++) {
                if(j-w[i]<0){
                    dp[i][j]=dp[i-1][j];
                }
                else {
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+w[i]);
                }
         }
    }
     
    printf("%d", v-dp[n][v]);
    
    return 0;
}

发表于 2024-11-30 12:06:24 回复(0)
不是哥们儿我是真无语了,所有货物加起来83,总容量90,你给我19的参考答案???
发表于 2024-09-26 17:59:16 回复(2)
#include <iostream>
#include<vector>
using namespace std;
int main() {
      int n,V,num;
      cin>>V;
      cin>>n;
      vector<int> v(V+1,0);
      for(int i=0;i<n;i++)
      {
        cin>>num;
        for(int j=V;j>=num;j--)
        {
            v[j]=max(v[j],v[j-num]+num);
        }
      }
      cout<<V-v[V];
      return 0;
}
// 有时候真的很难说,对于这个你一定不能想具体了,而是要抽象的想,最小剩余空间不就是最大空间存放量吗,
//对于每一步的箱子容量大小,从第一步开始就要是最大的,而后对于数字的替换算法,则用了j-num表示
//它逻辑隐式的改变了数字的存在大小,很6
编辑于 2024-04-17 19:45:56 回复(0)
import sys
#dp[i][j]表示前i个商品在背包容量j下占用的最大体积

bag = int(input())
n = int(input())
item = []
for _ in range(n):
item.append(int(input()))
dp = [[0] * (bag+1) for _ in range(n)]

for i in range(n):
for j in range(bag+1):
if(j == 0):
dp[i][j] = 0
continue
if(i == 0 and j >= item[i]):
dp[i][j] = item[i]
elif (j >= item[i]):
dp[i][j] = max(dp[i-1][j], dp[i-1][j-item[i]]+item[i])
else:
dp[i][j] = dp[i-1][j]

print(bag - dp[n-1][bag])

发表于 2023-06-09 00:38:17 回复(0)
package main

import (
    "fmt"
)

func main() {
    var v int
    fmt.Scan(&v)
    var n int
    fmt.Scan(&n)
    arr:=make([]int,n)
    for i:=0;i<n;i++{
        fmt.Scan(&arr[i])
    }
    dp:=make([]int,v+1)
    for _,x:=range arr{
        for i:=v;i>=x;i--{
            dp[i]=max(dp[i],x+dp[i-x])
        }
    }
    fmt.Print(v-dp[v])
}

func max(a,b int)int{
    if a>b{
        return a
    }
    return b
}

发表于 2023-02-12 11:37:05 回复(0)
#include <iostream>
using namespace std;
const int N = 20010;
int f[N];
int main()
{
    int n, m;
    cin >> m >> n;
    for(int i = 1; i <= n; i++)
    {
        int v;
        cin >> v;
        for(int j = m; j >= v; j--)
            f[j] = max(f[j], f[j - v] + v);
    }
    cout << m - f[m] << endl;
}

发表于 2022-11-27 20:04:58 回复(0)
def 省空间解法():
    # f[i][j]表示背包容量为j时,前i个物品能放的最小剩余空间
    f = [V for i in range(V + 1)]
    for i in range(1, n + 1):
        for j in range(V, a[i]-1, -1):  # 注意这边要逆序
            f[j] = min(f[j], f[j - a[i]] - a[i])
    print(f[V])


def 常规解法():
    # f[i][j]表示背包容量为j时,前i个物品能放的最小剩余空间
    f = [[V for i in range(V + 1)] for j in range(n + 1)]
    for i in range(1, n + 1):
        for j in range(0, V + 1):
            if j >= a[i]:
                f[i][j] = min(f[i - 1][j], f[i - 1][j - a[i]] - a[i])
            else:
                f[i][j] = f[i - 1][j]
    print(f[n][V])


if __name__ == "__main__":
    V = int(input())
    n = int(input())
    a = [0]
    for i in range(n):
        a.append(int(input()))
    # V, n = 10, 3
    # a = [0, 4, 8, 5]
    # 常规解法()
    省空间解法()

发表于 2022-09-16 09:45:22 回复(0)
#include <stdio.h>
int max(int a, int b){
    if (a >=b ){return a;}
    return b;
    }
int fdp(int* v,int V,int n,int* dp){
    for(int i = 0;i < n ;i++)
    {
        for(int j = V;j >= v[i];j--)
        {
            dp[j] = max(dp[j],dp[j-v[i]] + v[i]);
        }
    }
    return dp[V];
}
int main(){
    int V,n;
    
    scanf("%d%d",&V,&n);
    int dp[V+1];
    memset(dp,0,sizeof(dp));
    int v[n];
    for(int i=0;i<n;i++){
        scanf("%d",&v[i]);
    }
     
    printf("%d",V-fdp(v,V,n,dp));             //1
    return 0;
}
发表于 2022-08-22 18:18:39 回复(0)
#include<iostream>
using namespace std;
int n,a[32],rest,ans;
void dp(int i){
    if(i==n)return;
    dp(i+1);
    if(rest-a[i]>=0){
        rest-=a[i];
    ans=min(ans,rest);
    dp(i+1);
    rest+=a[i];
    }
}
int main(){
    cin>>rest>>n;
    ans=rest;
    for(int i=0;i<n;i++)
        cin>>a[i];
    dp(0);
    cout<<ans;
    return 0;
}

发表于 2022-07-27 14:13:39 回复(0)
bigBox = int(input())
n= int(input())
box=[]
for x in range(n):
    box.append(int(input()))
# box.sort()
dp =[0]*(bigBox+2)
dp[0]=1 ##不装
for b in box:  
    j = bigBox
    while j>=b:
        if dp[j]==0:
            dp[j]= dp[j-b]
        j-=1
i=bigBox
while not dp[i]:
    i-=1
print(bigBox-i)

https://www.bilibili.com/video/BV12S4y1i7B9/?
发表于 2022-06-27 00:15:54 回复(0)