package com.zy.asrs.utils; import java.util.*; public class OptimizedLockerPackingUtils { 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; long bindingTags; Map contents; Set itemTypes; public Locker(int id) { this.id = id; this.remainingSpace = 1.0; this.contents = new HashMap<>(); this.itemTypes = new HashSet<>(); this.bindingTags = System.currentTimeMillis(); } 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); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("储物柜").append(id).append(": "); sb.append(String.format("剩余空间%.4f", remainingSpace)).append("\n"); for (Map.Entry entry : contents.entrySet()) { sb.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("个\n"); } return sb.toString(); } } static class PackingSolution { List lockers; int totalLockersUsed; double overallUtilization; int itemTypeChanges; int pureLockers; // 纯种类储物柜数量 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; pureLockers = 0; String lastItemType = null; for (Locker locker : lockers) { totalUsedSpace += (1.0 - locker.remainingSpace); // 统计纯种类储物柜 if (locker.itemTypes.size() == 1) { pureLockers++; } 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(pureLockers).append("个\n"); sb.append("平均空间利用率: ").append(String.format("%.2f", overallUtilization * 100)).append("%\n"); sb.append("物品种类切换次数: ").append(itemTypeChanges).append("次\n\n"); // 先显示纯种类储物柜,再显示混合储物柜 List pureLockersList = new ArrayList<>(); List mixedLockersList = new ArrayList<>(); for (Locker locker : lockers) { if (locker.itemTypes.size() == 1) { pureLockersList.add(locker); } else { mixedLockersList.add(locker); } } sb.append("【纯种类储物柜】:\n"); for (Locker locker : pureLockersList) { sb.append(locker.toString()).append("\n"); } sb.append("【混合储物柜】:\n"); for (Locker locker : mixedLockersList) { 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 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 = optimizedPacking(items); System.out.println("\n" + solution); scanner.close(); } /** * 优化装箱算法:先集中处理同种物品,最后处理余料 */ public static PackingSolution optimizedPacking(List items) { List 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; // 计算这种物品需要多少个完整的储物柜 int fullLockersNeeded = item.remaining / item.maxCapacity; int remainder = item.remaining % item.maxCapacity; // 分配完整储物柜 for (int i = 0; i < fullLockersNeeded; i++) { Locker locker = new Locker(lockerId++); locker.addItem(item, item.maxCapacity); solution.addLocker(locker); } // 如果有余料,暂时保留(第二阶段处理) } // 第二阶段:收集所有余料 List remainingItems = new ArrayList<>(); for (Item item : itemsToPack) { if (item.remaining > 0) { remainingItems.add(item); } } // 如果还有余料,用最佳适应算法处理 if (!remainingItems.isEmpty()) { processRemainingItems(remainingItems, solution, lockerId); } return solution; } /** * 处理剩余物品(余料) */ private static void processRemainingItems(List remainingItems, PackingSolution solution, int startLockerId) { int lockerId = startLockerId; // 按空间占用从大到小排序(优先处理大物品) remainingItems.sort((a, b) -> Double.compare(b.unitSpace, a.unitSpace)); for (Item item : remainingItems) { while (item.remaining > 0) { // 优先尝试放入已有同种物品的储物柜 Locker sameTypeLocker = findSameTypeLocker(solution, item); if (sameTypeLocker != null) { int maxCanAdd = (int) Math.floor(sameTypeLocker.remainingSpace / item.unitSpace); int actualAdd = Math.min(item.remaining, maxCanAdd); sameTypeLocker.addItem(item, actualAdd); continue; } // 其次尝试放入现有储物柜(最佳适应) Locker bestLocker = findBestLocker(solution, item); if (bestLocker != null) { int maxCanAdd = (int) Math.floor(bestLocker.remainingSpace / item.unitSpace); int actualAdd = Math.min(item.remaining, maxCanAdd); bestLocker.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); } } } /** * 寻找已有同种物品的储物柜 */ private static Locker findSameTypeLocker(PackingSolution solution, Item item) { Locker bestLocker = null; double bestRemaining = -1; for (Locker locker : solution.lockers) { if (locker.containsItemType(item.name) && locker.canAdd(item, 1)) { if (locker.remainingSpace > bestRemaining) { bestLocker = locker; bestRemaining = locker.remainingSpace; } } } return bestLocker; } /** * 寻找最佳适应的储物柜 */ private static Locker findBestLocker(PackingSolution solution, Item item) { 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; } } return bestLocker; } /** * 高级优化:智能余料分配 */ public static PackingSolution advancedOptimizedPacking(List items) { List itemsToPack = new ArrayList<>(); for (Item item : items) { itemsToPack.add(new Item(item.name, item.maxCapacity, item.stock)); } PackingSolution solution = new PackingSolution(); int lockerId = 1; // 第一阶段:集中处理每种物品 Map remainders = new HashMap<>(); for (Item item : itemsToPack) { if (item.remaining == 0) continue; int fullLockers = item.remaining / item.maxCapacity; int remainder = item.remaining % item.maxCapacity; for (int i = 0; i < fullLockers; i++) { Locker locker = new Locker(lockerId++); locker.addItem(item, item.maxCapacity); solution.addLocker(locker); } if (remainder > 0) { remainders.put(item.name, remainder); } } // 第二阶段:智能余料分配 if (!remainders.isEmpty()) { smartRemainderProcessing(remainders, itemsToPack, solution, lockerId); } return solution; } /** * 智能余料处理:尝试将余料组合成完整储物柜 */ private static void smartRemainderProcessing(Map remainders, List items, PackingSolution solution, int startLockerId) { int lockerId = startLockerId; // 尝试找到可以完美组合的余料 boolean foundCombination; do { foundCombination = false; // 寻找可以填满一个储物柜的余料组合 for (Item item1 : items) { if (remainders.getOrDefault(item1.name, 0) == 0) continue; for (Item item2 : items) { if (item1.name.equals(item2.name) || remainders.getOrDefault(item2.name, 0) == 0) continue; double spaceNeeded = remainders.get(item1.name) * item1.unitSpace + remainders.get(item2.name) * item2.unitSpace; if (spaceNeeded <= 1.0 + 1e-6) { // 考虑浮点误差 Locker locker = new Locker(lockerId++); locker.addItem(item1, remainders.get(item1.name)); locker.addItem(item2, remainders.get(item2.name)); solution.addLocker(locker); remainders.put(item1.name, 0); remainders.put(item2.name, 0); foundCombination = true; break; } } if (foundCombination) break; } } while (foundCombination); // 处理剩余的零散余料 for (Item item : items) { int remainder = remainders.getOrDefault(item.name, 0); if (remainder > 0) { Locker bestLocker = findBestLockerForRemainder(solution, item, remainder); if (bestLocker != null) { bestLocker.addItem(item, remainder); } else { Locker newLocker = new Locker(lockerId++); newLocker.addItem(item, remainder); solution.addLocker(newLocker); } } } } private static Locker findBestLockerForRemainder(PackingSolution solution, Item item, int quantity) { Locker bestLocker = null; double bestFit = Double.MAX_VALUE; for (Locker locker : solution.lockers) { if (locker.canAdd(item, quantity)) { double remainingAfterAdd = locker.remainingSpace - quantity * item.unitSpace; if (remainingAfterAdd < bestFit) { bestLocker = locker; bestFit = remainingAfterAdd; } } } return bestLocker; } /** * 性能测试和比较 */ public static void performanceTest() { System.out.println("=== 性能测试 ==="); // 测试数据 List testItems = Arrays.asList( new Item("X", 20, 87), new Item("Y", 15, 63), new Item("Z", 34, 125), new Item("T", 25, 48), new Item("U", 40, 92) ); System.out.println("测试物品数量: " + testItems.size()); int totalItems = testItems.stream().mapToInt(item -> item.stock).sum(); System.out.println("总物品数量: " + totalItems); long startTime = System.currentTimeMillis(); PackingSolution solution = optimizedPacking(testItems); long endTime = System.currentTimeMillis(); System.out.println("\n优化算法结果:"); System.out.println("处理时间: " + (endTime - startTime) + "ms"); System.out.println("储物柜数量: " + solution.totalLockersUsed); System.out.println("纯种类储物柜: " + solution.pureLockers); System.out.println("空间利用率: " + String.format("%.2f", solution.overallUtilization * 100) + "%"); } }