1. 程式人生 > >三維裝箱問題Java程式碼的簡單實現過程(程式碼)

三維裝箱問題Java程式碼的簡單實現過程(程式碼)

  兩年前發了篇關於三維裝箱的日記,許諾過要分享程式碼的,結果一直沒發,後來居然忘記了。一直有人加我QQ來的,這幾年都用微信了,直到最近才發現這個問題,

  千萬不要輕易許諾別人什麼,否則事後真的很難兌現,兩年前的欠下的程式碼,今天,還了罷。為了我寫了好久的,腦力不夠了,空間感不強,為了遍歷一件商品和一個箱子之間的空間關係,參考16年7月6日的那篇《三維裝箱問題Java程式碼的簡單實現過程》我還做了兩個簡陋的紙盒,一個代表箱子,一個代表商品。擺弄了好久。也不知道對不對,貿然發帖,表示抱歉。

package com.windowdb.wms.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
 * 商品裝箱服務 討論請加QQ群:865601737
 * 
 * @author 竹林春雨-WindowDB.com
 * 
 *
 */
@SuppressWarnings({ "serial", "unused" })
public class GoodsInBox {
    /* 箱子的型號,盛放空間 */
    private Map<Integer, Map<String, Object>> boxTypeArr;
    /* 訂單中的商品 */
    private Map<Integer, Map<String, Integer>> orderItemArr;
    /* 計算結果 */
    private Map<String/* 箱子的型號 */, Integer/* 需要幾個 */> result = new HashMap<String, Integer>();
    /* 計算過程資料,有效的空間列表 */
    private List<String> inboxinfo = new ArrayList<String>();

    /**
     * 根據箱型以及訂單中的商品,返回每個箱型需要箱子多少隻。如果沒有任何的箱子能裝下某一款超大商品的時候,丟擲異常
     * 
     * @param linkedHashMap
     * @param orderItemArr
     * @return
     */
    public GoodsInBox(LinkedHashMap<Integer, Map<String, Object>> linkedHashMap,
            Map<Integer, Map<String, Integer>> orderItemArr) {
        this.boxTypeArr = linkedHashMap;
        this.orderItemArr = orderItemArr;
        // 開始執行
        run();
    }

    // 執行裝箱
    private void run() {
        Integer[] boxkeys = boxTypeArr.keySet().toArray(new Integer[] {});
        aBoxType: for (Integer boxkey : boxkeys) {
            tryInSpance(boxTypeArr.get(boxkey), orderItemArr);
        }

    }

    /**
     * 每次測試1塊空間,和全部商品,將商品依次向空間轉移,放進去後產生新的3塊空間, 同時商品的數量再減少,直到商品全部轉移;
     * 
     * @param space1
     * @param gs
     * @return
     */
    private void tryInSpance(Map<String/* 長l寬w高h */, Object/* 釐米 */> space1/* 某1個盒子或者是1個剩餘空間 */,
            Map<Integer, Map<String, Integer>> gs/* 多件商品,裝進去一件,刪除一件,直到刪沒了為止 */) {
        if (null == space1 || null == gs) {
            return;
        }
        java.util.Iterator<Integer> gks = gs.keySet().iterator();
        while (gks.hasNext()) {
            Integer oid = gks.next();
            Map<String, Integer> g = gs.get(oid);
            // 商品數量
            Integer num = g.get("n");
            if (0 == num) {

                return;
            }
            // 多少件商品就迴圈多少次,每次處理一件;
            for (int i = num; i > 0; i--) {
                String boxcode = space1.get("boxcode").toString().concat(":").concat(oid.toString());
                Integer bl = Integer.valueOf(space1.get("l").toString());
                Integer bw = Integer.valueOf(space1.get("w").toString());
                Integer bh = Integer.valueOf(space1.get("h").toString());
                Integer gl = g.get("l");
                Integer gw = g.get("w");
                Integer gh = g.get("h");
                // 正面放置商品
                if ((bl - gl) >= 0 && (bw - gw) >= 0 && (bh - gh) >= 0) {
                    // 可以放入的情況下先減少商品的數量;
                    g.put("n", i - 1);
                    // 加入統計
                    inboxinfo.add(boxcode);
                    // 正放的3塊剩餘空間
                    Map<String, Object> leftover;
                    // 第一塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-1:").concat(oid.toString()));
                    leftover.put("l", gl);
                    leftover.put("w", gw);
                    leftover.put("h", bh - gh);
                    tryInSpance(leftover, gs);
                    // 第二塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-2:").concat(oid.toString()));
                    leftover.put("l", gl);
                    leftover.put("w", bw - gw);
                    leftover.put("h", bh);
                    tryInSpance(leftover, gs);
                    // 第三塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-3:").concat(oid.toString()));
                    leftover.put("l", bl - gl);
                    leftover.put("w", bw);
                    leftover.put("h", bh);
                    tryInSpance(leftover, gs);

                    // 側面放置商品
                } else if ((bl - gw) >= 0 && (bw - gl) >= 0 && (bh - gh) >= 0) {
                    // 可以放入的情況下先減少商品的數量;
                    g.put("n", i - 1);
                    // 加入統計
                    inboxinfo.add(boxcode);
                    // 側放的3塊剩餘空間
                    Map<String, Object> leftover;
                    // 第一塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-1:").concat(oid.toString()));
                    leftover.put("l", gl);
                    leftover.put("w", gw);
                    leftover.put("h", bh - gh);
                    tryInSpance(leftover, gs);
                    // 第二塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-2:").concat(oid.toString()));
                    leftover.put("l", bw - gl);
                    leftover.put("w", gw);
                    leftover.put("h", bh);
                    tryInSpance(leftover, gs);

                    // 第三塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-3:").concat(oid.toString()));
                    leftover.put("l", bl - gw);
                    leftover.put("w", bw);
                    leftover.put("h", bh);
                    tryInSpance(leftover, gs);

                    // 臥倒放置商品
                } else if (g.get("t") == 1 && (bl - gh) >= 0 && (bw - gw) >= 0 && (bw - gl) >= 0) {
                    // 可以放入的情況下先減少商品的數量;
                    g.put("n", i - 1);
                    // 加入統計
                    inboxinfo.add(boxcode);
                    // 側放的3塊剩餘空間
                    Map<String, Object> leftover;
                    // 第一塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-1:").concat(oid.toString()));
                    leftover.put("l", gh);
                    leftover.put("w", gw);
                    leftover.put("h", bh - gh);
                    tryInSpance(leftover, gs);

                    // 第二塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-2:").concat(oid.toString()));
                    leftover.put("l", bw - gw);
                    leftover.put("w", gh);
                    leftover.put("h", bh);
                    tryInSpance(leftover, gs);

                    // 第三塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-3:").concat(oid.toString()));
                    leftover.put("l", bl - gh);
                    leftover.put("w", bw);
                    leftover.put("h", bh);
                    tryInSpance(leftover, gs);

                    // 側臥放置商品
                } else if (g.get("t") == 1 && (bl - gw) >= 0 && (bh - gl) >= 0 && (bw - gh) >= 0) {
                    // 可以放入的情況下先減少商品的數量;
                    g.put("n", i - 1);
                    // 加入統計
                    inboxinfo.add(boxcode);
                    // 側放的3塊剩餘空間
                    Map<String, Object> leftover;
                    // 第一塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-1:").concat(oid.toString()));
                    leftover.put("l", gw);
                    leftover.put("w", gh);
                    leftover.put("h", bh - gl);
                    tryInSpance(leftover, gs);
                    // 第二塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-2:").concat(oid.toString()));
                    leftover.put("l", bw - gh);
                    leftover.put("w", gw);
                    leftover.put("h", bh);
                    tryInSpance(leftover, gs);
                    // 第三塊空間
                    leftover = new HashMap<String, Object>();
                    leftover.put("boxcode", boxcode.concat("-3:").concat(oid.toString()));
                    leftover.put("l", bl - gw);
                    leftover.put("w", bw);
                    leftover.put("h", bh);
                    tryInSpance(leftover, gs);

                }
            }
        }
    }

    /**
     * 返回計算後得到的結果
     * 
     * @return
     */
    public Map<String/* 箱子的型號 */, Integer/* 需要幾個 */> getResult() {
        result.clear();
        // 這裡開始數數了!
        // 所有裝入盒子的商品都放到列表中了,
        // length為特定長度(3)的為商品第一次裝入箱子,其它過長(>3)的都是小件商品塞到之前的箱子裡的。
        // 以上執行的結果應該是:最少需要1號箱兩個,3號箱1個,
        for (String code : inboxinfo) {
            if (code.length() == 3) {
                String boxno = String.valueOf(code.split(":")[0]);
                Integer num = result.get(boxno);
                if (null == num)
                    num = 0;
                num = num + 1;
                result.put(boxno + "", num);
            }
        }
        return this.result;
    }

    public static void main(String args[]) throws Exception {

        GoodsInBox gb = new GoodsInBox(/* 箱子的規格 */new LinkedHashMap<Integer, Map<String, Object>>() {
            {
                // 假設有大中小三種型號的箱子,如下描述:
                /*-
                 *  要求資料從資料庫中取出來的時候是按照 箱子型號大小系數 (l長+w款+h高) 從小到大的順序排好序的。這樣裝箱後可以得到近似合理的解
                 */
                // 1,小箱
                this.put(1, new LinkedHashMap<String, Object>() {
                    {
                        // 小箱 長 100釐米,寬100釐米,高120釐米;
                        this.put("boxcode", 1);
                        this.put("l", 100);
                        this.put("w", 100);
                        this.put("h", 120);
                    }
                });
                // 2,中箱
                this.put(2, new LinkedHashMap<String, Object>() {
                    {
                        // 中箱 長200釐米,寬150釐米,高180釐米
                        this.put("boxcode", 2);
                        this.put("l", 200);
                        this.put("w", 150);
                        this.put("h", 180);
                    }
                });
                // 3,大箱
                this.put(3, new LinkedHashMap<String, Object>() {
                    {
                        // 大箱長500釐米寬600釐米高700釐米
                        this.put("boxcode", 3);
                        this.put("l", 500);
                        this.put("w", 600);
                        this.put("h", 700);
                    }
                });

            }
        }, /* 訂單 */ new LinkedHashMap<Integer, Map<String, Integer>>() {
            {
                /*-
                 *  要求資料從資料庫中取出來的時候是按照 商品大小系數 (l長+w款+h高) 從大到小的順序排好序的。這樣裝箱後可以得到近似合理的解
                 */
                // 1,臥室用的小冰箱1個
                this.put(1, new LinkedHashMap<String, Integer>() {
                    {
                        // 長 400釐米,寬500釐米,高600釐米;
                        this.put("l", 400);
                        this.put("w", 500);
                        this.put("h", 600);
                        this.put("n", 1);
                        this.put("t", 0);// 是否可以躺著放,0,否;1,是,這個不能躺著放,而且所有商品均不能倒置,而且倒置和正著放置所佔用空間一樣。
                    }
                });
                // 1,電腦主機箱2臺
                this.put(2, new LinkedHashMap<String, Integer>() {
                    {
                        // 長 57釐米,寬21釐米,高52釐米;
                        this.put("l", 57);
                        this.put("w", 21);
                        this.put("h", 52);
                        this.put("n", 2);
                        this.put("t", 1);// 是否可以躺著放,0,否;1,是
                    }
                });
                // 2,蘋果膝上型電腦10臺
                this.put(3, new LinkedHashMap<String, Integer>() {
                    {
                        // 長 33釐米,寬24釐米,高6釐米;
                        this.put("l", 33);
                        this.put("w", 24);
                        this.put("h", 6);
                        this.put("n", 10);
                        this.put("t", 1);// 是否可以躺著放,0,否;1,是
                    }
                });
                // 3,青軸小鍵盤10個
                this.put(4, new LinkedHashMap<String, Integer>() {
                    {
                        // 長 39釐米,寬15釐米,高5釐米;
                        this.put("l", 39);
                        this.put("w", 15);
                        this.put("h", 5);
                        this.put("n", 10);
                        this.put("t", 1);// 是否可以躺著放,0,否;1,是
                    }
                });

            }
        });
        
        // 1號箱子 2只,分別裝筆記本和小鍵盤; 3號箱子:1只用來裝冰箱
        System.out.println(JSONObject.fromObject(gb.getResult()).toString());

    }
}

對加我QQ的幾位同學表示歉意!超時了,同意不了。有問題直接發到QQ群:865601737,或者郵箱我都可以。