三維裝箱問題Java程式碼的簡單實現過程(程式碼)
阿新 • • 發佈:2018-12-11
兩年前發了篇關於三維裝箱的日記,許諾過要分享程式碼的,結果一直沒發,後來居然忘記了。一直有人加我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,或者郵箱我都可以。