DP(二)装箱问题

这篇博客探讨了一种经典的计算机科学问题——物品装箱问题,通过使用动态规划和逆序求最大容量的策略来找到解决方案。博主介绍了两种不同的方法,一种是基于01背包的动态规划思路,另一种是通过逆序求解最大容量的优化方法。这两种方法的时间复杂度都是O(n*m),并给出了C++和Java的实现代码示例。文章适合对算法和数据结构感兴趣的读者学习。
摘要由CSDN通过智能技术生成

题目描述
有一个箱子容量为 V,同时有 n 个物品,每个物品有一个体积(正整数)。

要求 n 个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。

输入格式
第一行是一个整数 V,表示箱子容量。

第二行是一个整数 n,表示物品数。

接下来 n 行,每行一个正整数(不超过10000),分别表示这 n 个物品的各自体积。

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

数据范围
0<V≤20000,
0<n≤30

样例
输入样例:
24
6
8
3
12
7
9
7
输出样例:
0

思路一:DP
那么显而易见我们要让物品的体积尽量大,所以体积就是价值。
但是我们选一个物品,首先我们收获了价值,但箱子的体积也相应的减少了容量,所以体积还是价值。
意味着我们在让箱子剩余体积减少时,还能装的容量减少了(怎么这么不通顺)。
那就是01背包了。
只不过这里体积也是价值

时间复杂度 O(n*m)
参考文献
C++ 代码

#include <iostream>

using namespace std;

const int N = 40, M = 10010;
int n, m;
int a[N];
int f[N][M * 2];
//f[i][j]表示考虑前i个物品,总体积不超过j的最大体积。
int main() {
    cin >> m >> n;
    for (int i = 1; i <= n; i ++ ) cin >> a[i];

    for (int i = 1; i <= n; i ++ ) {
        for (int j = 1; j <= m; j ++ ) {
            f[i][j] = f[i - 1][j];
            //不选当前物品
            if (j >= a[i]) f[i][j] = max(f[i][j], f[i - 1][j - a[i]] + a[i]);
            //选当前物品,但体积必须足够
        }
    }
    cout << m - f[n][m] << endl; //注意是剩余体积
    return 0;
}

//优化
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int f[N];
int n,m;
int main()
{
    cin>>m>>n;
    memset(f,0,sizeof f);
    for (int i = 0; i < n; i ++ )
    {
        int v;
        cin>>v;
        for (int j = m; j>=v; j -- )
         f[j]=max(f[j],f[j-v]+v);
    }
    return cout<<m-f[m],0;
}

Java代码

import java.util.*;
import java.io.*;
public class Main{
    static int m,n;
    static int f[]=new int [100010];
    public static void main(String[] args){
        Scanner cin = new Scanner(System.in);
        m=cin.nextInt();
        n=cin.nextInt();
        for(int i=0;i<n;i++)
        {
            int a=cin.nextInt();
            for(int j=m;j>=a;j--)
            f[j]=Math.max(f[j],f[j-a]+a);
        }
        System.out.println(m-f[m]);
        return ;
    }
}

思路二:逆序求最大容量
01背包f[j]表示容量为j的背包最多能装多少价值的物品
而下面的f[j]表示容量为j的背包是否能被装满
能想到这个也是非常nb的

时间复杂度 O(n*m)
参考文献
C++ 代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int m,n;
int f[N];
int main()
{
    cin>>m>>n;
    f[0]=1;
    for (int i = 0; i < n; i ++ )
    {
        int v;
        cin>>v;
        for (int j = m; j >=v; j --)
         f[j]|=f[j-v];
    }
    for (int j = m; j; j --)
        if(f[j])
            return cout<<m-j,0;
    return 0;
}

Java代码

import java.util.*;
import java.io.*;
public class Main{
    static int m,n;
    static int f[]=new int [100010];
    public static void main(String[] args){
        Scanner cin = new Scanner(System.in);
        m=cin.nextInt();
        n=cin.nextInt();
        f[0]=1;
        for(int i=0;i<n;i++)
        {
            int a=cin.nextInt();
            for(int j=m;j>=a;j--)
            f[j]|=f[j-a];
        }
        for (int j = m; j>=0; j --)
          if(f[j]==1)
          {
              System.out.println(m-j);
              return ;
          }
        return ;
    }
}

欢迎留言点赞

嗷嗷嗷~

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
装箱问题,也称为维货物堆码或维空间装载问题,是一个典型的优化问题,目标是最大化货物的装载效率,通常涉及到货物的尺寸、箱子的大小以及容器的空间布局。非线性规划方法在这种情况下常用于解决,因为装载空间限制和货物堆叠规则形成了一种非线性的约束条件。 解决装箱问题的非线性规划常见思路包括: 1. **整数编程(Integer Programming, IP)**:将问题转化为一个整数线性规划问题,利用求解器如CPLEX、Gurobi等来寻找最优解。这种方法可能不适合大规模问题,因为整数解搜索通常较慢。 2. **动态规划(Dynamic Programming, DP)**:对于具有重叠子问题的情况,可以使用DP方法构建决策树,逐级选择最优的装载策略。但是,DP可能需要存储大量的中间结果,计算复杂度较高。 3. **模拟退火算法(Simulated Annealing, SA)**:这是一种启发式搜索算法,通过随机化策略跳出局部最优解,逐步接近全局最优。适用于问题规模较大且有大量局部最优的情况。 4. **遗传算法(Genetic Algorithm, GA)**:通过自然选择、交叉和变异操作搜索解空间,适用于具有多峰性或复杂约束的优化问题。 5. **蚁群算法(Ant Colony Optimization, ACO)**:模仿蚂蚁寻找食物的行为,通过概率更新策略找到较好的装载方案。 6. **基于局部搜索的方法**:如 tabu search 或 2-opt 算法,从初始状态开始,通过一系列局部改进操作优化装载。 **相关问题--:** 1. 在装箱问题中,如何定义状态和动作? 2. 如何处理货物的不规则形状和优先级需求? 3. 非线性规划方法与线性规划相比,有哪些优势和劣势?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值