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<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<>();
|
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<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;
|
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<Locker> pureLockersList = new ArrayList<>();
|
List<Locker> 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<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 = optimizedPacking(items);
|
System.out.println("\n" + solution);
|
|
scanner.close();
|
}
|
|
/**
|
* 优化装箱算法:先集中处理同种物品,最后处理余料
|
*/
|
public static PackingSolution optimizedPacking(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;
|
|
// 计算这种物品需要多少个完整的储物柜
|
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<Item> 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<Item> 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<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;
|
|
// 第一阶段:集中处理每种物品
|
Map<String, Integer> 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<String, Integer> remainders,
|
List<Item> 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<Item> 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) + "%");
|
}
|
}
|