贪心算法实现装箱问题

实验要求


 

实验 2:装箱问题
[实验目的]
1. 练习贪婪法求解
2. 练习链表的使用
[实验题目]
装箱问题可简述如下:设有编号为 0、1、…、n-1 的 n 种物品,体积分别为
v0、v1、…、vn-1。将这 n 种物品装到容量都为 V 的若干箱子里。约定这 n 种物品的
体积均不超过 V,即对于 0≤i<n,有 0<vi≤v。不同的装箱方案所需要的箱子数
目可能不同。装箱问题要求使装尽这 n 种物品的箱子数要少。
[算法分析]
贪婪法是一种不追求最优解,只希望得到较为满意解的方法。贪婪法一般可
以快速得到满意的解,因为它省去了为找最优解要穷尽所有可能而必须耗费的大
量时间。贪婪法常以当前情况为基础作最优选择,而不考虑各种可能的整体情况,
所以贪婪法不要回溯。
例如平时购物找钱时,为使找回的零钱的硬币数最少,不考虑找零钱的所有
各种发表方案,而是从最大面值的币种开始,按递减的顺序考虑各币种,先尽量
用大面值的币种,当不足大面值币种的金额时才去考虑下一种较小面值的币种。
这就是在使用贪婪法。这种方法在这里总是最优,是因为银行对其发行的硬币种
类和硬币面值的巧妙安排。如只有面值分别为 1、5 和 11 单位的硬币,而希望找
回总额为 15 单位的硬币。按贪婪算法,应找 1 个 11 单位面值的硬币和 4 个 1 单
位面值的硬币,共找回 5 个硬币。但最优的解应是 3 个 5 单位面值的硬币。
若考察将 n 种物品的集合分划成 n 个或小于 n 个物品的所有子集,最优解就
可以找到。但所有可能划分的总数太大。对适当大的 n,找出所有可能的划分要花
费的时间是无法承受的。为此,对装箱问题采用非常简单的近似算法,即贪婪法。
该算法依次将物品放到它第一个能放进去的箱子中,该算法虽不能保证找到最优
解,但还是能找到非常好的解。不失一般性,设 n 件物品的体积是按从大到小排
好序的,即有 v0≥v1≥…≥vn-1。如不满足上述要求,只要先对这 n 件物品按它们
的体积从大到小排序,然后按排序结果对物品重新编号即可。装箱算法简单描述
如下:
{
输入箱子的容积;
输入物品种数 n;
按体积从大到小顺序,输入各物品的体积;
预置已用箱子链为空;
预置已用箱子计数器 box_count 为 0;
for
(i=0;i<n;i++)
{
从已用的第一只箱子开始顺序寻找能放入物品 i
的箱子 j;
if
(已用箱子都不能再放物品 i)4
{
另用一个箱子,并将物品 i 放入该箱子;
box_count++;
}
else
将物品 i 放入箱子 j;
}
}
 
 
实现代码
import java.util.*;

public class box {
    public static void main(String[] args) {
        ArrayList<Integer> weight = new ArrayList<>(); // 存放物品重量的
        ArrayList<Integer> x = new ArrayList<>(); //存放是否取出
        Integer box = 0;
        ArrayList<Integer[]> boxx = new ArrayList<>(); // 存放具体的物品
        int i = 0; //第几位
        Integer V = 0;  // 箱子重量
        Scanner sc = new Scanner(System.in);

        //将箱子重量赋值
        System.out.println("请输入箱子的容积:");
        V = Integer.valueOf(sc.next());
        box = V;

        //输入物品重量
        System.out.println("请输入物品的重量(结束请按'0'):");
        while (true) {
            if (sc.hasNext()) {
                int num = sc.nextInt();
                if (num == 0) {
                    break;
                }
                weight.add(num);
                x.add(1);
            }
        }
        System.out.println("----------");
        sort(weight);
        System.out.println("物体重量为:");
        for (Integer j :
                weight) {
            System.out.print(j + "  ");
        }

        IN(weight,box,boxx);

        int size = boxx.size();
        for (int j = 0; j < size; j++) {
            Integer[] values = boxx.get(j);
            System.out.println();
            System.out.println("方法"+j+"为:");
            for (int k = 0; k < values.length; k++) {

                System.out.print(" -- " + values[k] + " -- ");
            }
        }

    }

    /**
     *
     * @param weight 剩余的箱子的重量
     * @param box 箱子的容积
     * @param boxx 装入箱子的分组
     */
    private static void IN(ArrayList<Integer> weight,Integer box,ArrayList<Integer[]> boxx) {
        if (weight.size() == 0){
            return;
        }
        ArrayList<Integer> x = new ArrayList<>(); //添加数组
        Integer boxcopy = box;

        int k = weight.size();
        //不能用Itero迭代器,会出bug的,只能用for循环,使用数组删除也不行,会将重复的数据全部删除
        for (int i = 0,j = 0;i < k ;i++){
            if (box >= weight.get(j) ){
                box -= weight.get(j);
                x.add(weight.get(j));
                weight.remove(j);
            }else{
                j++;
            }
        }

        boxx.add(become_In(x));
        IN(weight,boxcopy,boxx);
    }

    /**
     * 排序,将sort方法进行重写,变成从大到小
     * @param weight
     */
    private static void sort(ArrayList<Integer> weight) {
        weight.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                if (o1 > o2) {
                    //从大到小
                    return -1;
                } else {
                    return 1;
                }
            }
        });
    }

    /**
     * 将arraylist转换为integer【】
     * @param x 传入的需要转换形式的数组
     * @return 返回值
     */
    private static Integer[] become_In(ArrayList<Integer> x){
        Integer[] arr = x.toArray(new Integer[x.size()]);
        return arr;
    }

}
装箱问题

 

posted @ 2022-05-08 08:46  七色angel  阅读(308)  评论(0编辑  收藏  举报