import java.util.*;
import java.util.stream.Collectors;
// 托盘类
class Pallet {
private String palletId;
private List<Fixture> fixtures;
private List<Material> materials;
public Pallet(String palletId) {
this.palletId = palletId;
this.fixtures = new ArrayList<>();
this.materials = new ArrayList<>();
}
// getter和setter方法
public String getPalletId() {
return palletId;
}
public List<Fixture> getFixtures() {
return fixtures;
}
public List<Material> getMaterials() {
return materials;
}
@Override
public String toString() {
return "托盘[" + palletId + "]";
}
}
// 工装类
class Fixture {
private String code;
private String model;
private String type;
public Fixture(String code, String model, String type) {
this.code = code;
this.model = model;
this.type = type;
}
public Fixture() {
}
public Fixture(String code) {
this.code = code;
}
public String getCode() {
return code;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Fixture fixture = (Fixture) o;
return Objects.equals(code, fixture.code);
}
@Override
public int hashCode() {
return Objects.hash(code);
}
public void setCode(String code) {
this.code = code;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
// 辅料类
class Material {
private String code;
private String uniqueCode;
public Material(String code) {
this.code = code;
}
public String getCode() {
return code;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Material material = (Material) o;
return Objects.equals(code, material.code);
}
@Override
public int hashCode() {
return Objects.hash(code);
}
}
// 出库服务
public class PalletOutboundService {
/**
* 优化托盘出库
* @param inventory 库存中的所有托盘
* @param requiredFixtures 需要的工装对象列表(可能只包含功能类型)
* @param requiredMaterialCodes 需要的辅料编码列表
* @return 最优的出库托盘列表
*/
public List<Pallet> optimizeOutbound(List<Pallet> inventory,
List<Fixture> requiredFixtures,
List<String> requiredMaterialCodes) {
// 分离具体编码和功能类型的工装需求
Set<String> requiredFixtureCodes = new HashSet<>();
Set<String> requiredFixtureTypes = new HashSet<>();
for (Fixture fixture : requiredFixtures) {
if (fixture.getCode() != null && !fixture.getCode().isEmpty()) {
requiredFixtureCodes.add(fixture.getCode());
} else if (fixture.getType() != null && !fixture.getType().isEmpty()) {
requiredFixtureTypes.add(fixture.getType());
}
}
// 处理辅料需求
Set<String> requiredMaterials = new HashSet<>(requiredMaterialCodes);
// 复制一份库存,避免修改原始数据
List<Pallet> inventoryCopy = new ArrayList<>(inventory);
// 尝试找到包含所有需求的单个托盘
Pallet perfectMatch = findPerfectMatch(inventoryCopy, requiredFixtureCodes, requiredFixtureTypes, requiredMaterials);
if (perfectMatch != null) {
return Collections.singletonList(perfectMatch);
}
// 使用贪心算法找到最优解
return findOptimalPallets(inventoryCopy, requiredFixtureCodes, requiredFixtureTypes, requiredMaterials);
}
/**
* 寻找完美匹配的托盘(包含所有需求)
*/
private Pallet findPerfectMatch(List<Pallet> inventory,
Set<String> requiredFixtureCodes,
Set<String> requiredFixtureTypes,
Set<String> requiredMaterials) {
for (Pallet pallet : inventory) {
// 检查是否满足所有编码需求
Set<String> palletFixtureCodes = pallet.getFixtures().stream()
.map(Fixture::getCode)
.collect(Collectors.toSet());
if (!palletFixtureCodes.containsAll(requiredFixtureCodes)) {
continue; // 不满足编码需求,跳过
}
// 检查是否满足所有类型需求
boolean allTypesMatched = true;
for (String type : requiredFixtureTypes) {
boolean typeMatched = pallet.getFixtures().stream()
.anyMatch(f -> type.equals(f.getType()));
if (!typeMatched) {
allTypesMatched = false;
break;
}
}
if (!allTypesMatched) {
continue; // 不满足类型需求,跳过
}
// 检查是否满足所有辅料需求
Set<String> palletMaterialCodes = pallet.getMaterials().stream()
.map(Material::getCode)
.collect(Collectors.toSet());
if (palletMaterialCodes.containsAll(requiredMaterials)) {
return pallet; // 找到完美匹配
}
}
return null; // 没有找到完美匹配
}
/**
* 使用贪心算法找到最优的托盘组合
*/
private List<Pallet> findOptimalPallets(List<Pallet> inventory,
Set<String> requiredFixtureCodes,
Set<String> requiredFixtureTypes,
Set<String> requiredMaterials) {
List<Pallet> selectedPallets = new ArrayList<>();
Set<String> remainingFixtureCodes = new HashSet<>(requiredFixtureCodes);
Set<String> remainingFixtureTypes = new HashSet<>(requiredFixtureTypes);
Set<String> remainingMaterials = new HashSet<>(requiredMaterials);
// 当还有未满足的需求时继续循环
while (!remainingFixtureCodes.isEmpty() || !remainingFixtureTypes.isEmpty() || !remainingMaterials.isEmpty()) {
// 找到最佳托盘(包含最多未满足需求的托盘)
Pallet bestPallet = null;
int maxMatchCount = 0;
for (Pallet pallet : inventory) {
int matchCount = countMatches(pallet, remainingFixtureCodes, remainingFixtureTypes, remainingMaterials);
if (matchCount > maxMatchCount) {
maxMatchCount = matchCount;
bestPallet = pallet;
}
}
// 如果找不到匹配的托盘,说明无法满足所有需求
if (bestPallet == null || maxMatchCount == 0) {
throw new RuntimeException("无法满足所有出库需求");
}
// 添加最佳托盘到结果中
selectedPallets.add(bestPallet);
// 更新剩余需求
updateRemainingRequirements(bestPallet, remainingFixtureCodes, remainingFixtureTypes, remainingMaterials);
// 从库存中移除已选择的托盘
inventory.remove(bestPallet);
}
return selectedPallets;
}
/**
* 计算托盘中匹配的需求数量
*/
private int countMatches(Pallet pallet,
Set<String> remainingFixtureCodes,
Set<String> remainingFixtureTypes,
Set<String> remainingMaterials) {
int count = 0;
Set<String> matchedTypes = new HashSet<>();
// 计算匹配的工装编码数量
for (Fixture fixture : pallet.getFixtures()) {
if (remainingFixtureCodes.contains(fixture.getCode())) {
count++;
}
}
// 计算匹配的工装类型数量
for (Fixture fixture : pallet.getFixtures()) {
if (fixture.getType() != null &&
remainingFixtureTypes.contains(fixture.getType()) &&
!matchedTypes.contains(fixture.getType())) {
count++;
matchedTypes.add(fixture.getType());
}
}
// 计算匹配的辅料数量
for (Material material : pallet.getMaterials()) {
if (remainingMaterials.contains(material.getCode())) {
count++;
}
}
return count;
}
/**
* 更新剩余需求
*/
private void updateRemainingRequirements(Pallet pallet,
Set<String> remainingFixtureCodes,
Set<String> remainingFixtureTypes,
Set<String> remainingMaterials) {
// 移除已满足的工装编码需求
for (Fixture fixture : pallet.getFixtures()) {
remainingFixtureCodes.remove(fixture.getCode());
}
// 移除已满足的工装类型需求
Set<String> matchedTypes = new HashSet<>();
for (Fixture fixture : pallet.getFixtures()) {
if (fixture.getType() != null &&
remainingFixtureTypes.contains(fixture.getType()) &&
!matchedTypes.contains(fixture.getType())) {
remainingFixtureTypes.remove(fixture.getType());
matchedTypes.add(fixture.getType());
}
}
// 移除已满足的辅料需求
for (Material material : pallet.getMaterials()) {
remainingMaterials.remove(material.getCode());
}
}
// 测试方法
public static void main(String[] args) {
// 创建模拟数据库
// 创建一些工装和辅料
Fixture f1 = createFixture("F001", "型号A", "夹具");
Fixture f2 = createFixture("F002", "型号B", "治具");
Fixture f3 = createFixture("F003", "型号C", "模具");
Fixture f4 = createFixture("F004", "型号D", "夹具");
Fixture f5 = createFixture("F005", "型号E", "治具");
Fixture f6 = createFixture("F006", "型号E", "其他");
Material m1 = new Material("M001");
Material m2 = new Material("M002");
Material m3 = new Material("M003");
// 创建托盘并添加工装和辅料
Pallet p1 = new Pallet("P001");
p1.getFixtures().add(f1);
p1.getFixtures().add(f2);
p1.getMaterials().add(m1);
Pallet p2 = new Pallet("P002");
p2.getFixtures().add(f2);
p2.getFixtures().add(f4);
p2.getMaterials().add(m2);
Pallet p3 = new Pallet("P003");
p3.getFixtures().add(f3);
p3.getFixtures().add(f5);
p3.getMaterials().add(m3);
Pallet p4= new Pallet("P004");
p4.getFixtures().add(f6);
// 创建库存
List<Pallet> inventory = Arrays.asList(p1, p2, p3, p4);
// 创建出库服务
PalletOutboundService service = new PalletOutboundService();
// 测试场景1:需要F001, F002和M001(应该只出库P001)
List<Fixture> requiredFixtures1 = Arrays.asList(
createFixture("F001", null, null),
createFixture("F002", null, null)
);
List<String> requiredMaterials1 = Arrays.asList("M001");
System.out.println("测试场景1:按编码匹配");
List<Pallet> result1 = service.optimizeOutbound(inventory, requiredFixtures1, requiredMaterials1);
System.out.println("出库托盘数量: " + result1.size());
for (Pallet p : result1) {
System.out.println(p);
}
// 测试场景2:需要F001, F002, F003和M001, M003(应该出库P001和P003)
List<Fixture> requiredFixtures2 = Arrays.asList(
createFixture("F001", null, null),
createFixture("F002", null, null),
createFixture("F003", null, null)
);
List<String> requiredMaterials2 = Arrays.asList("M001", "M003");
System.out.println("\n测试场景2:按编码匹配多个托盘");
List<Pallet> result2 = service.optimizeOutbound(inventory, requiredFixtures2, requiredMaterials2);
System.out.println("出库托盘数量: " + result2.size());
for (Pallet p : result2) {
System.out.println(p);
}
// 测试场景3:按类型匹配 - 需要一个"夹具"类型的工装和M002(应该出库P002)
List<Fixture> requiredFixtures3 = Arrays.asList(
createFixture(null, null, "夹具")
);
List<String> requiredMaterials3 = Arrays.asList("M002");
System.out.println("\n测试场景3:按类型匹配");
List<Pallet> result3 = service.optimizeOutbound(inventory, requiredFixtures3, requiredMaterials3);
System.out.println("出库托盘数量: " + result3.size());
for (Pallet p : result3) {
System.out.println(p);
}
// 测试场景4:混合匹配 - 需要一个"夹具"类型和一个F003编码的工装,以及M001(应该出库P001和P003)
List<Fixture> requiredFixtures4 = Arrays.asList(
createFixture(null, null, "夹具"),
createFixture("F003", null, null)
);
List<String> requiredMaterials4 = Arrays.asList("M001");
System.out.println("\n测试场景4:混合匹配(类型+编码)");
List<Pallet> result4 = service.optimizeOutbound(inventory, requiredFixtures4, requiredMaterials4);
System.out.println("出库托盘数量: " + result4.size());
for (Pallet p : result4) {
System.out.println(p);
}
// 测试场景5:多类型匹配 - 需要一个"夹具"和一个"治具"类型的工装(应该只出库P001或P002)
List<Fixture> requiredFixtures5 = Arrays.asList(
createFixture(null, null, "模具"),
createFixture(null, null, "治具"),
createFixture(null, null, "其他")
);
List<String> requiredMaterials5 = Arrays.asList();
System.out.println("\n测试场景5:多类型匹配");
List<Pallet> result5 = service.optimizeOutbound(inventory, requiredFixtures5, requiredMaterials5);
System.out.println("出库托盘数量: " + result5.size());
for (Pallet p : result5) {
System.out.println(p);
}
// 测试场景6:
List<String> requiredMaterials6 = Arrays.asList("M001","M002");
System.out.println("\n测试场景6:单个辅料");
List<Pallet> result6 = service.optimizeOutbound(inventory, new ArrayList<>(), requiredMaterials6);
System.out.println("出库托盘数量: " + result6.size());
for (Pallet p : result6) {
System.out.println(p);
}
}
/**
* 创建工装对象
*/
private static Fixture createFixture(String code, String model, String type) {
Fixture fixture = new Fixture();
fixture.setCode(code);
fixture.setModel(model);
fixture.setType(type);
return fixture;
}