From dfed6fe975deaabb6c7ac424d7c0b7119543abba Mon Sep 17 00:00:00 2001 From: L <L@123> Date: 星期一, 13 十月 2025 13:26:26 +0800 Subject: [PATCH] * --- src/main/java/com/zy/asrs/utils/GroupedLockerOptimizerUtils.java | 466 +++++++++++++++++++++++++++++ src/main/java/com/zy/asrs/task/OrderToSortLineScheduler.java | 131 +++----- src/main/java/com/zy/asrs/utils/MultiLockerOptimizerUtils.java | 286 +++++++++++++++++ src/main/java/com/zy/asrs/utils/ToSortLineUtils.java | 64 ++++ 4 files changed, 865 insertions(+), 82 deletions(-) diff --git a/src/main/java/com/zy/asrs/task/OrderToSortLineScheduler.java b/src/main/java/com/zy/asrs/task/OrderToSortLineScheduler.java index add09c1..0be1ef1 100644 --- a/src/main/java/com/zy/asrs/task/OrderToSortLineScheduler.java +++ b/src/main/java/com/zy/asrs/task/OrderToSortLineScheduler.java @@ -12,6 +12,8 @@ import com.zy.asrs.service.impl.OrderDetlServiceImpl; import com.zy.asrs.task.core.ReturnT; import com.zy.asrs.task.handler.OrderToLineHandler; +import com.zy.asrs.utils.GroupedLockerOptimizerUtils; +import com.zy.asrs.utils.ToSortLineUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; @@ -35,7 +37,6 @@ @Autowired private BasArmMastSignService basArmMastSignService; - @Scheduled(cron = "0/3 * * * * ? ") private void orderToSortLine() { //鑾峰彇鏈笅鍙戝崟鎹� @@ -47,94 +48,60 @@ //閬嶅巻鍗曟嵁 for (String orderNo : orderNos) { - List<OrderDetl> orderDetls = orderDetlService.selectByOrderNo(orderNo); - OrderToLine orderToLine = new OrderToLine(); - orderToLine.setOrderNo(orderNo); //鍗曟嵁缂栧彿 - orderToLine.setCreateTime(System.currentTimeMillis()); //鍒涘缓鏃堕棿 - - Long bindingTag = System.currentTimeMillis();//娣锋惌鏍囪 - - List<OrderToLine.MatList> matLists = new ArrayList<>(); - List<OrderToLine.MatList> matListsRemainder = new ArrayList<>(); - List<OrderDetl> orderDetlsRemainder = new ArrayList<>(); - - for (OrderDetl orderDetl : orderDetls) { - Integer number = basArmRulesService.getNumber(orderDetl.getWeight(),orderDetl.getVolume(),orderDetl.getManLength(),orderDetl.getWidth(),orderDetl.getHeight()); - if (number == null) { - BasArmRules basArmRules = new BasArmRules(); - basArmRules.setMaterialHeight(orderDetl.getHeight()); - basArmRules.setMaterialWeight(orderDetl.getWeight()); - basArmRules.setMaterialLength(orderDetl.getManLength()); - basArmRules.setMaterialWidth(orderDetl.getWidth()); - basArmRulesService.insert(basArmRules); - return; - } else if (number == 0){ - return; - } - Double anfme = orderDetl.getAnfme(); - Double remainder = anfme % number; //鍙栦綑 浣欐暟娣锋惌 -// remainder = 0D; - if(!remainder.equals(0D)){ - // 缁勮鐗╂枡淇℃伅 - OrderToLine.MatList matMix = new OrderToLine.MatList( - orderDetl.getMatnr(), // matnr -> sku - orderDetl.getStandby1(), // supp -> po - orderDetl.getAnfme(), // 浣欐枡 -> 鍓╀綑浣欐枡缁熶竴鏃堕棿鎴虫爣璁� - orderDetl.getStandby2(), //barcode -> upc 鏉$爜 - 1, - null, //origin -> supplier 璐ф簮 - bindingTag //浣欐枡鏍囪鐩稿悓 - ); -// matListsRemainder.add(matMix); -// orderDetlsRemainder.add(orderDetl); - matLists.add(matMix); - } else { - Double ctns = anfme - remainder; - // 缁勮鐗╂枡淇℃伅 - OrderToLine.MatList mat = new OrderToLine.MatList( - orderDetl.getMatnr(), // matnr -> sku - orderDetl.getStandby1(), // supp -> po - orderDetl.getAnfme(), //鏁存枡 - orderDetl.getStandby2(), //barcode -> upc - 1, - null, //origin -> supplier 璐ф簮 - System.currentTimeMillis() - ); - matLists.add(mat); - } - } -// // 鏅鸿兘鍒嗙粍浣欐枡 -// if (matListsRemainder.size() > 0) { -// groupRemainders(orderDetlsRemainder, orderDetlsRemainder.size(), orderDetls.size(), matLists); -// } - orderToLine.setMatList(matLists); try{ - ReturnT<String> returnT = orderToLineHandler.start(orderToLine); - if (!returnT.isSuccess()) { - log.error("涓嬪彂鍗曟嵁澶辫触===>"+ JSON.toJSON(orderToLine)); - } - try{ - for (OrderToLine.MatList matList:orderToLine.getMatList()){ - BasArmMastSign basArmMastSign = new BasArmMastSign(); - basArmMastSign.setMatnr(matList.getSku()); - basArmMastSign.setOrderNo(orderToLine.getOrderNo()); - basArmMastSign.setSku(matList.getSku()); - basArmMastSign.setPo(matList.getPo()); - basArmMastSign.setUpc(matList.getUpc()); - basArmMastSign.setSupplier(matList.getSupplier()); - basArmMastSign.setStatus(0); - basArmMastSign.setCreateTime(matList.getBindingTags()); - basArmMastSignService.insert(basArmMastSign); + List<OrderDetl> orderDetls = orderDetlService.selectByOrderNo(orderNo); + List<GroupedLockerOptimizerUtils.Item> items = new ArrayList<>(); + for (OrderDetl orderDetl:orderDetls){ + Integer number = basArmRulesService.getNumber(orderDetl.getWeight(),orderDetl.getVolume(),orderDetl.getManLength(),orderDetl.getWidth(),orderDetl.getHeight()); + if (number == null) { + BasArmRules basArmRules = new BasArmRules(); + basArmRules.setMaterialHeight(orderDetl.getHeight()); + basArmRules.setMaterialWeight(orderDetl.getWeight()); + basArmRules.setMaterialLength(orderDetl.getManLength()); + basArmRules.setMaterialWidth(orderDetl.getWidth()); + basArmRulesService.insert(basArmRules); + return; + } else if (number == 0){ + return; } - }catch (Exception e){ + String name = ToSortLineUtils.MergerParameter(orderDetl.getMatnr(),orderDetl.getStandby1(),orderDetl.getStandby2()); + int maxCapacity = number; + int stock = orderDetl.getAnfme().intValue(); + items.add(new GroupedLockerOptimizerUtils.Item(name, maxCapacity, stock)); + } + OrderToLine orderToLine = new OrderToLine(); + orderToLine.setOrderNo(orderNo); //鍗曟嵁缂栧彿 + orderToLine.setCreateTime(System.currentTimeMillis()); //鍒涘缓鏃堕棿 + OrderToLine orderToLineR = ToSortLineUtils.GetOrderToLine(items, orderToLine); + + try{ + ReturnT<String> returnT = orderToLineHandler.start(orderToLineR); + if (!returnT.isSuccess()) { + log.error("涓嬪彂鍗曟嵁澶辫触===>"+ JSON.toJSON(orderToLineR)); + } else { + try{ + for (OrderToLine.MatList matList:orderToLineR.getMatList()){ + BasArmMastSign basArmMastSign = new BasArmMastSign(); + basArmMastSign.setMatnr(matList.getSku()); + basArmMastSign.setOrderNo(orderToLineR.getOrderNo()); + basArmMastSign.setSku(matList.getSku()); + basArmMastSign.setPo(matList.getPo()); + basArmMastSign.setUpc(matList.getUpc()); + basArmMastSign.setSupplier(matList.getSupplier()); + basArmMastSign.setStatus(0); + basArmMastSign.setCreateTime(matList.getBindingTags()); + basArmMastSignService.insert(basArmMastSign); + } + }catch (Exception e){} + } + } catch (Exception e){ + log.error("涓嬪彂鍗曟嵁寮傚父===>"+e.getMessage()); } } catch (Exception e){ - log.error("涓嬪彂鍗曟嵁寮傚父===>"+e.getMessage()); + log.error("涓嬪彂鍗曟嵁寮傚父,璺宠浆涓嬩竴涓鍗�===>"+e.getMessage()); } - } - } diff --git a/src/main/java/com/zy/asrs/utils/GroupedLockerOptimizerUtils.java b/src/main/java/com/zy/asrs/utils/GroupedLockerOptimizerUtils.java new file mode 100644 index 0000000..0512ba1 --- /dev/null +++ b/src/main/java/com/zy/asrs/utils/GroupedLockerOptimizerUtils.java @@ -0,0 +1,466 @@ +package com.zy.asrs.utils; + +import java.util.*; + +public class GroupedLockerOptimizerUtils { + + public static class Item { + String name; + double unitSpace; + int maxCapacity; + int stock; + int remaining; + + public Item(String name, int maxCapacity, int stock) { + this.name = name; + this.maxCapacity = maxCapacity; + this.unitSpace = 1.0 / maxCapacity; + this.stock = stock; + this.remaining = stock; + } + + @Override + public String toString() { + return name + "(鍗曟斁" + maxCapacity + "涓�, 搴撳瓨" + stock + "涓�)"; + } + } + + static class Locker { + int id; + double remainingSpace; + Map<String, Integer> contents; + Set<String> itemTypes; // 褰撳墠鍌ㄧ墿鏌滀腑鐨勭墿鍝佺绫� + + public Locker(int id) { + this.id = id; + this.remainingSpace = 1.0; + this.contents = new HashMap<>(); + this.itemTypes = new HashSet<>(); + } + + public boolean canAdd(Item item, int quantity) { + return remainingSpace >= quantity * item.unitSpace; + } + + public void addItem(Item item, int quantity) { + double spaceUsed = quantity * item.unitSpace; + remainingSpace -= spaceUsed; + contents.put(item.name, contents.getOrDefault(item.name, 0) + quantity); + itemTypes.add(item.name); + item.remaining -= quantity; + } + + // 妫�鏌ユ槸鍚﹀凡缁忓寘鍚绉嶇被鐨勭墿鍝� + public boolean containsItemType(String itemName) { + return itemTypes.contains(itemName); + } + + // 妫�鏌ユ槸鍚﹀彲浠ヤ紭鍏堟斁缃悓绉嶇墿鍝侊紙宸叉湁鍚岀鐗╁搧涓旇繕鏈夌┖闂达級 + public boolean canAddSameType(Item item) { + return containsItemType(item.name) && canAdd(item, 1); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("鍌ㄧ墿鏌�").append(id).append(": "); + sb.append(String.format("鍓╀綑绌洪棿%.4f", remainingSpace)).append("\n"); + for (Map.Entry<String, Integer> entry : contents.entrySet()) { + sb.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("涓猏n"); + } + return sb.toString(); + } + } + + static class PackingSolution { + List<Locker> lockers; + int totalLockersUsed; + double overallUtilization; + int itemTypeChanges; // 鐗╁搧绉嶇被鍒囨崲娆℃暟锛堣 閲忛泦涓害锛� + + public PackingSolution() { + this.lockers = new ArrayList<>(); + } + + public void addLocker(Locker locker) { + lockers.add(locker); + totalLockersUsed = lockers.size(); + } + + public void calculateMetrics() { + double totalUsedSpace = 0; + itemTypeChanges = 0; + String lastItemType = null; + + for (Locker locker : lockers) { + totalUsedSpace += (1.0 - locker.remainingSpace); + + for (String itemType : locker.itemTypes) { + if (lastItemType != null && !lastItemType.equals(itemType)) { + itemTypeChanges++; + } + lastItemType = itemType; + } + } + + overallUtilization = totalUsedSpace / totalLockersUsed; + } + + @Override + public String toString() { + calculateMetrics(); + StringBuilder sb = new StringBuilder(); + sb.append("=== 鍒嗙粍浼樺寲鎽嗘斁鏂规 ===\n"); + sb.append("浣跨敤鐨勫偍鐗╂煖鏁伴噺: ").append(totalLockersUsed).append("涓猏n"); + sb.append("骞冲潎绌洪棿鍒╃敤鐜�: ").append(String.format("%.2f", overallUtilization * 100)).append("%\n"); + sb.append("鐗╁搧绉嶇被鍒囨崲娆℃暟: ").append(itemTypeChanges).append("娆★紙瓒婂皯瓒婇泦涓級\n\n"); + + for (Locker locker : lockers) { + sb.append(locker.toString()).append("\n"); + } + return sb.toString(); + } + } + +// public static void main(String[] args) { +// Scanner scanner = new Scanner(System.in); +// +// System.out.println("璇疯緭鍏ョ墿鍝佺绫绘暟閲�:"); +// int itemTypes = scanner.nextInt(); +// scanner.nextLine(); +// +// List<Item> items = new ArrayList<>(); +// +// for (int i = 0; i < itemTypes; i++) { +// System.out.println("\n璇疯緭鍏ョ" + (i + 1) + "绉嶇墿鍝佺殑淇℃伅:"); +// System.out.print("鐗╁搧鍚嶇О: "); +// String name = scanner.nextLine(); +// +// System.out.print("鍗曠瀛樻斁鏈�澶ф暟閲�: "); +// int maxCapacity = scanner.nextInt(); +// +// System.out.print("搴撳瓨鏁伴噺: "); +// int stock = scanner.nextInt(); +// scanner.nextLine(); +// +// items.add(new Item(name, maxCapacity, stock)); +// } +// +// // 浣跨敤鍒嗙粍浼樺厛绠楁硶 +// PackingSolution solution = packItemsWithGrouping(items); +// +// System.out.println("\n" + solution); +// +// scanner.close(); +// } + public static void main(String[] args) { + int itemTypes = 5; + + List<Item> items = new ArrayList<>(); + + for (int i = 0; i < itemTypes; i++) { + String name = i+"a"; + int maxCapacity = i*10; + int stock = i*11; + items.add(new Item(name, maxCapacity, stock)); + } + + // 浣跨敤鍒嗙粍浼樺厛绠楁硶 + PackingSolution solution = packItemsWithGrouping(items); + for (Locker locker:solution.lockers) { + for (String mantnr : locker.contents.keySet()){ + System.out.println(mantnr+"<===>"+locker.contents.get(mantnr)); + } + } + System.out.println("\n" + solution); + +// scanner.close(); + } + + /** + * 鍒嗙粍浼樺厛瑁呯绠楁硶 + * 浼樺厛灏嗗悓绉嶇墿鍝佹斁鍦ㄤ竴璧凤紝鍙湁鍦ㄤ笉寰楀凡鏃舵墠鍒嗗紑鏀剧疆 + */ + public static PackingSolution packItemsWithGrouping(List<Item> items) { + List<Item> itemsToPack = new ArrayList<>(); + for (Item item : items) { + itemsToPack.add(new Item(item.name, item.maxCapacity, item.stock)); + } + + PackingSolution solution = new PackingSolution(); + int lockerId = 1; + + // 绗竴闃舵锛氫紭鍏堝皾璇曞皢姣忕鐗╁搧瀹屾暣鏀惧叆涓�涓偍鐗╂煖 + for (Item item : itemsToPack) { + if (item.remaining == 0) continue; + + double totalSpaceNeeded = item.remaining * item.unitSpace; + + // 濡傛灉鎵�鏈夌墿鍝佽兘鏀惧叆涓�涓偍鐗╂煖 + if (totalSpaceNeeded <= 1.0) { + boolean placedInExisting = false; + + // 瀵绘壘宸叉湁鍌ㄧ墿鏌滐紙浼樺厛閫夋嫨绌虹殑锛� + for (Locker locker : solution.lockers) { + if (locker.contents.isEmpty() && locker.canAdd(item, item.remaining)) { + locker.addItem(item, item.remaining); + placedInExisting = true; + break; + } + } + + // 濡傛灉娌℃湁绌哄偍鐗╂煖锛屽垱寤烘柊鐨� + if (!placedInExisting) { + Locker newLocker = new Locker(lockerId++); + newLocker.addItem(item, item.remaining); + solution.addLocker(newLocker); + } + } + } + + // 绗簩闃舵锛氬鐞嗗墿浣欑墿鍝侊紙鏃犳硶瀹屾暣鏀惧叆涓�涓偍鐗╂煖鐨勶級 + for (Item item : itemsToPack) { + while (item.remaining > 0) { + // 浼樺厛灏濊瘯鏀惧叆宸叉湁鍚岀鐗╁搧鐨勫偍鐗╂煖 + Locker bestSameTypeLocker = null; + double bestSameTypeSpace = -1; + + for (Locker locker : solution.lockers) { + if (locker.containsItemType(item.name) && locker.canAdd(item, 1)) { + if (locker.remainingSpace > bestSameTypeSpace) { + bestSameTypeLocker = locker; + bestSameTypeSpace = locker.remainingSpace; + } + } + } + + if (bestSameTypeLocker != null) { + int maxCanAdd = (int) Math.floor(bestSameTypeLocker.remainingSpace / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + bestSameTypeLocker.addItem(item, actualAdd); + continue; + } + + // 鍏舵灏濊瘯鏀惧叆绌哄偍鐗╂煖锛堜紭鍏堥泦涓斁缃級 + Locker emptyLocker = null; + for (Locker locker : solution.lockers) { + if (locker.contents.isEmpty() && locker.canAdd(item, 1)) { + emptyLocker = locker; + break; + } + } + + if (emptyLocker != null) { + int maxCanAdd = (int) Math.floor(emptyLocker.remainingSpace / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + emptyLocker.addItem(item, actualAdd); + continue; + } + + // 鏈�鍚庡皾璇曟斁鍏ヤ换浣曟湁绌洪棿鐨勫偍鐗╂煖 + Locker bestLocker = null; + double bestRemaining = Double.MAX_VALUE; + + for (Locker locker : solution.lockers) { + if (locker.canAdd(item, 1) && locker.remainingSpace < bestRemaining) { + bestLocker = locker; + bestRemaining = locker.remainingSpace; + } + } + + if (bestLocker != null) { + int maxCanAdd = (int) Math.floor(bestLocker.remainingSpace / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + bestLocker.addItem(item, actualAdd); + } else { + // 鍒涘缓鏂板偍鐗╂煖 + Locker newLocker = new Locker(lockerId++); + int maxCanAdd = (int) Math.floor(1.0 / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + newLocker.addItem(item, actualAdd); + solution.addLocker(newLocker); + } + } + } + + return solution; + } + + /** + * 鎸夌绫婚『搴忓鐞嗙畻娉� + * 鍏堝鐞嗕竴绉嶇墿鍝侊紝鍐嶅鐞嗕笅涓�绉� + */ + public static PackingSolution packItemsByType(List<Item> items) { + List<Item> itemsToPack = new ArrayList<>(); + for (Item item : items) { + itemsToPack.add(new Item(item.name, item.maxCapacity, item.stock)); + } + + PackingSolution solution = new PackingSolution(); + int lockerId = 1; + + // 鎸夌绫婚『搴忓鐞� + for (Item item : itemsToPack) { + while (item.remaining > 0) { + // 浼樺厛浣跨敤褰撳墠姝e湪澶勭悊璇ョ被鐗╁搧鐨勫偍鐗╂煖 + Locker currentTypeLocker = null; + for (Locker locker : solution.lockers) { + if (locker.containsItemType(item.name) && locker.canAdd(item, 1)) { + currentTypeLocker = locker; + break; + } + } + + if (currentTypeLocker != null) { + int maxCanAdd = (int) Math.floor(currentTypeLocker.remainingSpace / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + currentTypeLocker.addItem(item, actualAdd); + continue; + } + + // 濡傛灉娌℃湁鍚岀鐗╁搧鐨勫偍鐗╂煖锛屾壘绌哄偍鐗╂煖 + Locker emptyLocker = null; + for (Locker locker : solution.lockers) { + if (locker.contents.isEmpty()) { + emptyLocker = locker; + break; + } + } + + if (emptyLocker != null) { + int maxCanAdd = (int) Math.floor(emptyLocker.remainingSpace / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + emptyLocker.addItem(item, actualAdd); + continue; + } + + // 鍒涘缓鏂板偍鐗╂煖涓撻棬鏀捐繖绉嶇墿鍝� + Locker newLocker = new Locker(lockerId++); + int maxCanAdd = (int) Math.floor(1.0 / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + newLocker.addItem(item, actualAdd); + solution.addLocker(newLocker); + } + } + + return solution; + } + + /** + * 姣旇緝涓嶅悓绠楁硶鐨勬晥鏋� + */ + public static void compareAlgorithms() { + System.out.println("=== 绠楁硶姣旇緝 ==="); + + List<Item> testItems = Arrays.asList( + new Item("X", 20, 35), + new Item("Y", 15, 28), + new Item("Z", 34, 45), + new Item("T", 25, 18) + ); + + System.out.println("娴嬭瘯鐗╁搧: " + testItems); + + // 鍒嗙粍浼樺厛绠楁硶 + PackingSolution groupedSolution = packItemsWithGrouping(testItems); + System.out.println("\n鍒嗙粍浼樺厛绠楁硶:"); + System.out.println("鍌ㄧ墿鏌滄暟閲�: " + groupedSolution.totalLockersUsed); + System.out.println("绉嶇被鍒囨崲娆℃暟: " + groupedSolution.itemTypeChanges); + + // 鎸夌绫婚『搴忕畻娉� + PackingSolution typeOrderSolution = packItemsByType(testItems); + System.out.println("\n鎸夌绫婚『搴忕畻娉�:"); + System.out.println("鍌ㄧ墿鏌滄暟閲�: " + typeOrderSolution.totalLockersUsed); + System.out.println("绉嶇被鍒囨崲娆℃暟: " + typeOrderSolution.itemTypeChanges); + + // 鍘熷鏈�浣抽�傚簲绠楁硶锛堜笉鍒嗙粍锛� + PackingSolution originalSolution = packItemsOriginal(testItems); + System.out.println("\n鍘熷鏈�浣抽�傚簲绠楁硶:"); + System.out.println("鍌ㄧ墿鏌滄暟閲�: " + originalSolution.totalLockersUsed); + System.out.println("绉嶇被鍒囨崲娆℃暟: " + originalSolution.itemTypeChanges); + } + + /** + * 鍘熷鏈�浣抽�傚簲绠楁硶锛堜笉鍒嗙粍锛屼綔涓哄姣旓級 + */ + public static PackingSolution packItemsOriginal(List<Item> items) { + List<Item> itemsToPack = new ArrayList<>(); + for (Item item : items) { + itemsToPack.add(new Item(item.name, item.maxCapacity, item.stock)); + } + + // 鎸夌┖闂村崰鐢ㄤ粠澶у埌灏忔帓搴� + itemsToPack.sort((a, b) -> Double.compare(b.unitSpace, a.unitSpace)); + + PackingSolution solution = new PackingSolution(); + int lockerId = 1; + + for (Item item : itemsToPack) { + while (item.remaining > 0) { + Locker bestLocker = null; + double bestRemaining = Double.MAX_VALUE; + + for (Locker locker : solution.lockers) { + if (locker.canAdd(item, 1) && locker.remainingSpace < bestRemaining) { + bestLocker = locker; + bestRemaining = locker.remainingSpace; + } + } + + if (bestLocker != null) { + int maxCanAdd = (int) Math.floor(bestLocker.remainingSpace / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + bestLocker.addItem(item, actualAdd); + } else { + Locker newLocker = new Locker(lockerId++); + int maxCanAdd = (int) Math.floor(1.0 / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + newLocker.addItem(item, actualAdd); + solution.addLocker(newLocker); + } + } + } + + return solution; + } + + /** + * 鍙鍖栧睍绀哄偍鐗╂煖浣跨敤鎯呭喌 + */ +// public static void visualizeSolution(PackingSolution solution) { +// System.out.println("=== 鍌ㄧ墿鏌滀娇鐢ㄦ儏鍐靛彲瑙嗗寲 ==="); +// +// for (Locker locker : solution.lockers) { +// System.out.println("鍌ㄧ墿鏌� " + locker.id + ":"); +// for (Map.Entry<String, Integer> entry : locker.contents.entrySet()) { +// int barLength = (int) (entry.getValue() * 50 / (1.0 / 0.05)); // 绠�鍖栧彲瑙嗗寲 +// String bar = "=".repeat(barLength); +// System.out.printf(" %s: %s %d涓猏n", entry.getKey(), bar, entry.getValue()); +// } +// System.out.printf(" 鍓╀綑绌洪棿: %.2f%%\n", locker.remainingSpace * 100); +// System.out.println(); +// } +// } + + public static void visualizeSolution(PackingSolution solution) { + System.out.println("=== 鍌ㄧ墿鏌滀娇鐢ㄦ儏鍐靛彲瑙嗗寲 ==="); + + for (Locker locker : solution.lockers) { + System.out.println("鍌ㄧ墿鏌� " + locker.id + ":"); + for (Map.Entry<String, Integer> entry : locker.contents.entrySet()) { + int barLength = (int) (entry.getValue() * 50 / (1.0 / 0.05)); + + // 鏇夸唬 String.repeat() + StringBuilder barBuilder = new StringBuilder(); + for (int i = 0; i < barLength; i++) { + barBuilder.append("="); + } + String bar = barBuilder.toString(); + + System.out.printf(" %s: %s %d涓猏n", entry.getKey(), bar, entry.getValue()); + } + System.out.printf(" 鍓╀綑绌洪棿: %.2f%%\n", locker.remainingSpace * 100); + System.out.println(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/zy/asrs/utils/MultiLockerOptimizerUtils.java b/src/main/java/com/zy/asrs/utils/MultiLockerOptimizerUtils.java new file mode 100644 index 0000000..e0db69f --- /dev/null +++ b/src/main/java/com/zy/asrs/utils/MultiLockerOptimizerUtils.java @@ -0,0 +1,286 @@ +package com.zy.asrs.utils; +import java.util.*; + +public class MultiLockerOptimizerUtils { + + static class Item implements Comparable<Item> { + String name; + double unitSpace; + int maxCapacity; + int stock; + int remaining; // 鍓╀綑鏈憜鏀剧殑鏁伴噺 + + public Item(String name, int maxCapacity, int stock) { + this.name = name; + this.maxCapacity = maxCapacity; + this.unitSpace = 1.0 / maxCapacity; + this.stock = stock; + this.remaining = stock; + } + + // 鎸夌┖闂村崰鐢ㄤ粠澶у埌灏忔帓搴忥紙浼樺厛鏀惧崰鐢ㄥぇ鐨勶級 + @Override + public int compareTo(Item other) { + return Double.compare(other.unitSpace, this.unitSpace); + } + + @Override + public String toString() { + return name + "(鍗曟斁" + maxCapacity + "涓�, 搴撳瓨" + stock + "涓�)"; + } + } + + static class Locker { + int id; + double remainingSpace; + Map<String, Integer> contents; + + public Locker(int id) { + this.id = id; + this.remainingSpace = 1.0; + this.contents = new HashMap<>(); + } + + // 灏濊瘯鏀惧叆鐗╁搧 + public boolean canAdd(Item item, int quantity) { + return remainingSpace >= quantity * item.unitSpace; + } + + // 鏀惧叆鐗╁搧 + public void addItem(Item item, int quantity) { + double spaceUsed = quantity * item.unitSpace; + remainingSpace -= spaceUsed; + contents.put(item.name, contents.getOrDefault(item.name, 0) + quantity); + item.remaining -= quantity; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("鍌ㄧ墿鏌�").append(id).append(": "); + sb.append(String.format("鍓╀綑绌洪棿%.4f", remainingSpace)).append("\n"); + for (Map.Entry<String, Integer> entry : contents.entrySet()) { + sb.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("涓猏n"); + } + return sb.toString(); + } + } + + static class PackingSolution { + List<Locker> lockers; + int totalLockersUsed; + double overallUtilization; + + public PackingSolution() { + this.lockers = new ArrayList<>(); + } + + public void addLocker(Locker locker) { + lockers.add(locker); + totalLockersUsed = lockers.size(); + } + + public void calculateOverallUtilization() { + double totalUsedSpace = 0; + for (Locker locker : lockers) { + totalUsedSpace += (1.0 - locker.remainingSpace); + } + overallUtilization = totalUsedSpace / totalLockersUsed; + } + + @Override + public String toString() { + calculateOverallUtilization(); + StringBuilder sb = new StringBuilder(); + sb.append("=== 澶氬偍鐗╂煖鎽嗘斁鏂规 ===\n"); + sb.append("浣跨敤鐨勫偍鐗╂煖鏁伴噺: ").append(totalLockersUsed).append("涓猏n"); + sb.append("骞冲潎绌洪棿鍒╃敤鐜�: ").append(String.format("%.2f", overallUtilization * 100)).append("%\n\n"); + + for (Locker locker : lockers) { + sb.append(locker.toString()).append("\n"); + } + return sb.toString(); + } + } + + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + + System.out.println("璇疯緭鍏ョ墿鍝佺绫绘暟閲�:"); + int itemTypes = scanner.nextInt(); + scanner.nextLine(); + + List<Item> items = new ArrayList<>(); + + for (int i = 0; i < itemTypes; i++) { + System.out.println("\n璇疯緭鍏ョ" + (i + 1) + "绉嶇墿鍝佺殑淇℃伅:"); + System.out.print("鐗╁搧鍚嶇О: "); + String name = scanner.nextLine(); + + System.out.print("鍗曠瀛樻斁鏈�澶ф暟閲�: "); + int maxCapacity = scanner.nextInt(); + + System.out.print("搴撳瓨鏁伴噺: "); + int stock = scanner.nextInt(); + scanner.nextLine(); + + items.add(new Item(name, maxCapacity, stock)); + } + + // 浣跨敤鏈�浣抽�傚簲閫掑噺绠楁硶 + PackingSolution solution = packItems(items); + + System.out.println("\n" + solution); + + scanner.close(); + } + + /** + * 瑁呯绠楁硶锛氭渶浣抽�傚簲閫掑噺锛圔est Fit Decreasing锛� + * 杩欐槸瑁呯闂鐨勭粡鍏稿惎鍙戝紡绠楁硶 + */ + public static PackingSolution packItems(List<Item> items) { + // 澶嶅埗鐗╁搧鍒楄〃锛岄伩鍏嶄慨鏀瑰師濮嬫暟鎹� + List<Item> itemsToPack = new ArrayList<>(); + for (Item item : items) { + itemsToPack.add(new Item(item.name, item.maxCapacity, item.stock)); + } + + // 鎸夌墿鍝佸ぇ灏忎粠澶у埌灏忔帓搴忥紙浼樺厛澶勭悊澶х墿鍝侊級 + Collections.sort(itemsToPack); + + PackingSolution solution = new PackingSolution(); + int lockerId = 1; + + // 澶勭悊姣忕鐗╁搧 + for (Item item : itemsToPack) { + while (item.remaining > 0) { + // 瀵绘壘鏈�閫傚悎鐨勭幇鏈夊偍鐗╂煖 + Locker bestLocker = null; + double bestRemaining = Double.MAX_VALUE; + + for (Locker locker : solution.lockers) { + if (locker.canAdd(item, 1) && locker.remainingSpace < bestRemaining) { + bestLocker = locker; + bestRemaining = locker.remainingSpace; + } + } + + // 濡傛灉鎵惧埌鍚堥�傜殑鍌ㄧ墿鏌� + if (bestLocker != null) { + int maxCanAdd = (int) Math.floor(bestLocker.remainingSpace / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + bestLocker.addItem(item, actualAdd); + } else { + // 鍒涘缓鏂板偍鐗╂煖 + Locker newLocker = new Locker(lockerId++); + int maxCanAdd = (int) Math.floor(1.0 / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + newLocker.addItem(item, actualAdd); + solution.addLocker(newLocker); + } + } + } + + return solution; + } + + /** + * 鏇夸唬绠楁硶锛氶娆¢�傚簲閫掑噺锛團irst Fit Decreasing锛� + * 鍙︿竴绉嶅父鐢ㄧ殑瑁呯鍚彂寮忕畻娉� + */ + public static PackingSolution packItemsFirstFit(List<Item> items) { + List<Item> itemsToPack = new ArrayList<>(); + for (Item item : items) { + itemsToPack.add(new Item(item.name, item.maxCapacity, item.stock)); + } + + Collections.sort(itemsToPack); + + PackingSolution solution = new PackingSolution(); + int lockerId = 1; + + for (Item item : itemsToPack) { + while (item.remaining > 0) { + boolean placed = false; + + // 灏濊瘯鏀惧叆鐜版湁鍌ㄧ墿鏌� + for (Locker locker : solution.lockers) { + if (locker.canAdd(item, 1)) { + int maxCanAdd = (int) Math.floor(locker.remainingSpace / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + locker.addItem(item, actualAdd); + placed = true; + break; + } + } + + // 濡傛灉娌℃壘鍒板悎閫傜殑鍌ㄧ墿鏌滐紝鍒涘缓鏂扮殑 + if (!placed) { + Locker newLocker = new Locker(lockerId++); + int maxCanAdd = (int) Math.floor(1.0 / item.unitSpace); + int actualAdd = Math.min(item.remaining, maxCanAdd); + newLocker.addItem(item, actualAdd); + solution.addLocker(newLocker); + } + } + } + + return solution; + } + + /** + * 娴嬭瘯涓嶅悓鐨勮绠辩畻娉� + */ + public static void testDifferentAlgorithms() { + System.out.println("=== 绠楁硶姣旇緝娴嬭瘯 ==="); + + List<Item> testItems = Arrays.asList( + new Item("X", 20, 30), + new Item("Y", 15, 25), + new Item("Z", 34, 40), + new Item("T", 25, 15) + ); + + System.out.println("娴嬭瘯鐗╁搧: " + testItems); + + // 娴嬭瘯鏈�浣抽�傚簲绠楁硶 + PackingSolution bestFitSolution = packItems(testItems); + System.out.println("\n鏈�浣抽�傚簲绠楁硶缁撴灉:"); + System.out.println("浣跨敤鍌ㄧ墿鏌�: " + bestFitSolution.totalLockersUsed + "涓�"); + + // 娴嬭瘯棣栨閫傚簲绠楁硶 + PackingSolution firstFitSolution = packItemsFirstFit(testItems); + System.out.println("棣栨閫傚簲绠楁硶缁撴灉:"); + System.out.println("浣跨敤鍌ㄧ墿鏌�: " + firstFitSolution.totalLockersUsed + "涓�"); + + // 鏄剧ず鏈�浣崇畻娉曠殑璇︾粏鏂规 + System.out.println("\n鏈�浣虫柟妗堣鎯�:"); + System.out.println(bestFitSolution); + } + + /** + * 楠岃瘉鏄惁鎵�鏈夌墿鍝侀兘宸叉憜鏀� + */ + public static boolean validateSolution(List<Item> originalItems, PackingSolution solution) { + Map<String, Integer> totalPlaced = new HashMap<>(); + + for (Locker locker : solution.lockers) { + for (Map.Entry<String, Integer> entry : locker.contents.entrySet()) { + totalPlaced.put(entry.getKey(), + totalPlaced.getOrDefault(entry.getKey(), 0) + entry.getValue()); + } + } + + for (Item item : originalItems) { + if (totalPlaced.getOrDefault(item.name, 0) != item.stock) { + System.out.println("楠岃瘉澶辫触: " + item.name + " 搴旀斁" + item.stock + + "涓紝瀹炴斁" + totalPlaced.getOrDefault(item.name, 0) + "涓�"); + return false; + } + } + + System.out.println("楠岃瘉鎴愬姛: 鎵�鏈夌墿鍝侀兘宸叉纭憜鏀�"); + return true; + } +} \ No newline at end of file diff --git a/src/main/java/com/zy/asrs/utils/ToSortLineUtils.java b/src/main/java/com/zy/asrs/utils/ToSortLineUtils.java new file mode 100644 index 0000000..19ee586 --- /dev/null +++ b/src/main/java/com/zy/asrs/utils/ToSortLineUtils.java @@ -0,0 +1,64 @@ +package com.zy.asrs.utils; + +import com.zy.asrs.entity.OrderDetl; +import com.zy.asrs.entity.param.OrderToLine; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +public class ToSortLineUtils { + private static final String sign_F = "|F|LABEL_"; + + public static void main(String[] args) { + int itemTypes = 5; + + List<GroupedLockerOptimizerUtils.Item> items = new ArrayList<>(); + + for (int i = 0; i < itemTypes; i++) { + String name = i+"a"; + int maxCapacity = i*10; + int stock = i*11; + items.add(new GroupedLockerOptimizerUtils.Item(name, maxCapacity, stock)); + } + + // 浣跨敤鍒嗙粍浼樺厛绠楁硶 + GroupedLockerOptimizerUtils.PackingSolution solution = GroupedLockerOptimizerUtils.packItemsWithGrouping(items); + for (GroupedLockerOptimizerUtils.Locker locker:solution.lockers) { + for (String mantnr : locker.contents.keySet()){ + System.out.println(mantnr+"<===>"+locker.contents.get(mantnr)); + } + } + System.out.println("\n" + solution); + } + + public static String MergerParameter(String sku,String po,String upc){ + return sku+sign_F+po+sign_F+upc; + } + + public static OrderToLine GetOrderToLine(List<GroupedLockerOptimizerUtils.Item> items,OrderToLine orderToLine){ + Long bindingTag = System.currentTimeMillis();//娣锋惌鏍囪 + List<OrderToLine.MatList> matLists = new ArrayList<>(); + // 浣跨敤鍒嗙粍浼樺厛绠楁硶 + GroupedLockerOptimizerUtils.PackingSolution solution = GroupedLockerOptimizerUtils.packItemsWithGrouping(items); + for (GroupedLockerOptimizerUtils.Locker locker:solution.lockers) { + for (String mantnr : locker.contents.keySet()){ + System.out.println(mantnr+"<===>"+locker.contents.get(mantnr)); + String[] split = mantnr.split(Pattern.quote(sign_F)); + OrderToLine.MatList mat = new OrderToLine.MatList( + split[0], // matnr -> sku + split[1], // supp -> po -> s1 + locker.contents.get(mantnr).doubleValue(), //鏁存枡 + split[2], //barcode -> upc -> s2 + 1, + null, //origin -> supplier 璐ф簮 + bindingTag + ); + matLists.add(mat); + } + bindingTag++; + } + orderToLine.setMatList(matLists); + return orderToLine; + } +} -- Gitblit v1.9.1