java: Breadth First Search Algorithm and Depth First Search Algorithm
·
项目结构:

介绍了一套珠宝首饰智能包装配载系统的Java实现,主要包含以下内容:
-
系统架构:采用BFS、DFS和A*三种算法实现包装策略,支持多线程并发处理。
-
核心模块:
- 配置管理(AppConfig):日志路径、线程池大小等
- 枚举定义(ResultCode):标准化返回码
- 数据模型:首饰(JewelryItem)、包装规格(PackageSpec)、装箱约束(PackConstraint)等
- 算法实现:BfsStrategy、DfsStrategy、AStarStrategy三种策略
-
业务逻辑:
- 支持首饰体积计算
- 装箱约束校验
- 结果合并与日志记录
- 交互式控制台界面
-
技术特点:
- 单例模式管理资源
- 线程安全的任务池
- 支持多种数据库
- 详细的日志记录
系统可智能计算最优包装方案,考虑成本、优先级和库存等因素,适用于珠宝行业的包装配载需求。
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:25
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : AppConfig.java
* explain : 学习 类
**/
package BreadthFirst.config;
import java.io.File;
public class AppConfig {
public static final String LOG_SAVE_PATH = "./logs";
public static final String LOG_FILE_NAME = "jewelry_packer.log";
public static final boolean LOG_CONSOLE_ENABLE = true;
public static final boolean LOG_FILE_ENABLE = true;
public static final int MAX_WORKER_THREAD = 8;
public static final int MAX_SEARCH_STATE = 25000;
public static void initLogDir() {
File dir = new File(LOG_SAVE_PATH);
if (!dir.exists()) {
dir.mkdirs();
}
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:26
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : ResultCode.java
* explain : 学习 类
**/
package BreadthFirst.core.enums;
public record ResultCode(int code, String msg) {
public static final ResultCode SUCCESS = new ResultCode(0, "成功");
public static final ResultCode PARAM_ERROR = new ResultCode(400, "参数非法");
public static final ResultCode NO_AVAILABLE_PACKAGE = new ResultCode(401, "无可用包装规格");
public static final ResultCode CONSTRAINT_FAIL = new ResultCode(402, "装箱约束冲突,无法装载");
public static final ResultCode SEARCH_OVER_LIMIT = new ResultCode(501, "搜索状态超限,未找到方案");
public static final ResultCode NO_ANY_LOAD_PLAN = new ResultCode(502, "无法生成配载方案");
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:26
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : JewelryItem.java
* explain : 学习 类
**/
package BreadthFirst.core.models;
public class JewelryItem {
private String jewelryCode;
private double singleVolume;
private int quantity;
public double getTotalVolume() {
return singleVolume * quantity;
}
// getter & setter
public String getJewelryCode() {
return jewelryCode;
}
public void setJewelryCode(String jewelryCode) {
this.jewelryCode = jewelryCode;
}
public double getSingleVolume() {
return singleVolume;
}
public void setSingleVolume(double singleVolume) {
this.singleVolume = singleVolume;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:27
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : PackageSpec.java
* explain : 学习 类
**/
package BreadthFirst.core.models;
public class PackageSpec {
private String specCode;
private double volume;
private int stockQty;
private double unitCost;
private int priorityWeight;
public double getValidVolume(double coeff) {
return volume * coeff;
}
// getter & setter
public String getSpecCode() {
return specCode;
}
public void setSpecCode(String specCode) {
this.specCode = specCode;
}
public double getVolume() {
return volume;
}
public void setVolume(double volume) {
this.volume = volume;
}
public int getStockQty() {
return stockQty;
}
public void setStockQty(int stockQty) {
this.stockQty = stockQty;
}
public double getUnitCost() {
return unitCost;
}
public void setUnitCost(double unitCost) {
this.unitCost = unitCost;
}
public int getPriorityWeight() {
return priorityWeight;
}
public void setPriorityWeight(int priorityWeight) {
this.priorityWeight = priorityWeight;
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:26
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : PackConstraint.java
* explain : 学习 类
**/
package BreadthFirst.core.models;
public class PackConstraint {
private double bufferCoeff;
private int singleBoxMaxQty;
private boolean forbidMixJewelry;
private boolean forbidSplitJewelry;
// getter & setter
public double getBufferCoeff() {
return bufferCoeff;
}
public void setBufferCoeff(double bufferCoeff) {
this.bufferCoeff = bufferCoeff;
}
public int getSingleBoxMaxQty() {
return singleBoxMaxQty;
}
public void setSingleBoxMaxQty(int singleBoxMaxQty) {
this.singleBoxMaxQty = singleBoxMaxQty;
}
public boolean isForbidMixJewelry() {
return forbidMixJewelry;
}
public void setForbidMixJewelry(boolean forbidMixJewelry) {
this.forbidMixJewelry = forbidMixJewelry;
}
public boolean isForbidSplitJewelry() {
return forbidSplitJewelry;
}
public void setForbidSplitJewelry(boolean forbidSplitJewelry) {
this.forbidSplitJewelry = forbidSplitJewelry;
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:27
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : PackQueryCondition.java
* explain : 学习 类
**/
package BreadthFirst.core.models;
import BreadthFirst.core.strategy.LoadStrategyType;
import java.util.List;
public class PackQueryCondition {
private List<JewelryItem> jewelryList;
private PackConstraint constraint;
private double totalMaterialVol;
private List<PackageSpec> packageSpecList;
private LoadStrategyType strategyType;
private boolean allowOverLoad;
// getter & setter
public List<JewelryItem> getJewelryList() {
return jewelryList;
}
public void setJewelryList(List<JewelryItem> jewelryList) {
this.jewelryList = jewelryList;
}
public PackConstraint getConstraint() {
return constraint;
}
public void setConstraint(PackConstraint constraint) {
this.constraint = constraint;
}
public double getTotalMaterialVol() {
return totalMaterialVol;
}
public void setTotalMaterialVol(double totalMaterialVol) {
this.totalMaterialVol = totalMaterialVol;
}
public List<PackageSpec> getPackageSpecList() {
return packageSpecList;
}
public void setPackageSpecList(List<PackageSpec> packageSpecList) {
this.packageSpecList = packageSpecList;
}
public LoadStrategyType getStrategyType() {
return strategyType;
}
public void setStrategyType(LoadStrategyType strategyType) {
this.strategyType = strategyType;
}
public boolean isAllowOverLoad() {
return allowOverLoad;
}
public void setAllowOverLoad(boolean allowOverLoad) {
this.allowOverLoad = allowOverLoad;
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:29
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : PackResult.java
* explain : 学习 类
**/
package BreadthFirst.core.models;
import java.util.Dictionary;
import java.util.List;
import java.util.Map;
public class PackResult {
private int code;
private String msg;
private List<SingleUsePackage> usePackageList;
private double remainMaterialVol;
private Map<String, Integer> remainPackageStock;
private int totalUsePackageCnt;
private int searchStateCount;
private boolean fullLoadFlag;
private double jewelryTotalCalcVol;
private double totalCost;
// getter & setter
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public List<SingleUsePackage> getUsePackageList() {
return usePackageList;
}
public void setUsePackageList(List<SingleUsePackage> usePackageList) {
this.usePackageList = usePackageList;
}
public double getRemainMaterialVol() {
return remainMaterialVol;
}
public void setRemainMaterialVol(double remainMaterialVol) {
this.remainMaterialVol = remainMaterialVol;
}
public Map<String, Integer> getRemainPackageStock() {
return remainPackageStock;
}
public void setRemainPackageStock(Map<String, Integer> remainPackageStock) {
this.remainPackageStock = remainPackageStock;
}
public int getTotalUsePackageCnt() {
return totalUsePackageCnt;
}
public void setTotalUsePackageCnt(int totalUsePackageCnt) {
this.totalUsePackageCnt = totalUsePackageCnt;
}
public int getSearchStateCount() {
return searchStateCount;
}
public void setSearchStateCount(int searchStateCount) {
this.searchStateCount = searchStateCount;
}
public boolean isFullLoadFlag() {
return fullLoadFlag;
}
public void setFullLoadFlag(boolean fullLoadFlag) {
this.fullLoadFlag = fullLoadFlag;
}
public double getJewelryTotalCalcVol() {
return jewelryTotalCalcVol;
}
public void setJewelryTotalCalcVol(double jewelryTotalCalcVol) {
this.jewelryTotalCalcVol = jewelryTotalCalcVol;
}
public double getTotalCost() {
return totalCost;
}
public void setTotalCost(double totalCost) {
this.totalCost = totalCost;
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:29
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : SingleUsePackage.java
* explain : 学习 类
**/
package BreadthFirst.core.models;
public class SingleUsePackage {
private String specCode;
private double volume;
private double validVolume;
private int useCount;
private String belongJewelryCode;
// getter & setter
public String getSpecCode() {
return specCode;
}
public void setSpecCode(String specCode) {
this.specCode = specCode;
}
public double getVolume() {
return volume;
}
public void setVolume(double volume) {
this.volume = volume;
}
public double getValidVolume() {
return validVolume;
}
public void setValidVolume(double validVolume) {
this.validVolume = validVolume;
}
public int getUseCount() {
return useCount;
}
public void setUseCount(int useCount) {
this.useCount = useCount;
}
public String getBelongJewelryCode() {
return belongJewelryCode;
}
public void setBelongJewelryCode(String belongJewelryCode) {
this.belongJewelryCode = belongJewelryCode;
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:33
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : AStarStrategy.java
* explain : 学习 类
**/
package BreadthFirst.core.strategy;
import BreadthFirst.config.AppConfig;
import BreadthFirst.core.AppLogger;
import BreadthFirst.core.enums.ResultCode;
import BreadthFirst.core.models.*;
import java.util.*;
public class AStarStrategy implements IPackStrategy {
private final AppLogger logger = AppLogger.getInstance();
private record AStarItem(double f, int g, double loadVol, double cost, Map<String, Integer> usedMap) {
}
@Override
public PackResult execute(PackQueryCondition condition) {
double totalMatVol = condition.getTotalMaterialVol();
List<PackageSpec> specList = condition.getPackageSpecList();
PackConstraint cons = condition.getConstraint();
if (totalMatVol <= 0) {
PackResult res = new PackResult();
res.setCode(ResultCode.PARAM_ERROR.code());
res.setMsg(ResultCode.PARAM_ERROR.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>());
return res;
}
if (specList.isEmpty()) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_AVAILABLE_PACKAGE.code());
res.setMsg(ResultCode.NO_AVAILABLE_PACKAGE.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>());
return res;
}
Map<String, Integer> initStock = new HashMap<>();
Map<String, Double> specVolMap = new HashMap<>();
Map<String, Double> specCostMap = new HashMap<>();
Map<String, Integer> specWeightMap = new HashMap<>();
double bufferCoeff = cons != null ? cons.getBufferCoeff() : 1.0;
for (PackageSpec item : specList) {
initStock.put(item.getSpecCode(), item.getStockQty());
specVolMap.put(item.getSpecCode(), item.getValidVolume(bufferCoeff));
specCostMap.put(item.getSpecCode(), item.getUnitCost());
specWeightMap.put(item.getSpecCode(), item.getPriorityWeight());
}
int needCount = 0;
double singleVolume = 0;
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
JewelryItem item = condition.getJewelryList().get(0);
needCount = item.getQuantity();
singleVolume = item.getSingleVolume();
}
List<String> validSpecCodes = new ArrayList<>();
for (String code : specVolMap.keySet()) {
if (specVolMap.get(code) >= singleVolume) {
validSpecCodes.add(code);
}
}
if (validSpecCodes.isEmpty()) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_ANY_LOAD_PLAN.code());
res.setMsg(ResultCode.NO_ANY_LOAD_PLAN.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>(initStock));
res.setSearchStateCount(1);
return res;
}
validSpecCodes.sort((a, b) -> {
int costCompare = Double.compare(specCostMap.get(a), specCostMap.get(b));
if (costCompare != 0) return costCompare;
return Integer.compare(specWeightMap.get(b), specWeightMap.get(a));
});
String bestSpecCode = validSpecCodes.get(0);
int availableStock = initStock.get(bestSpecCode);
if (needCount <= availableStock) {
Map<String, Integer> remainStock = new HashMap<>(initStock);
remainStock.put(bestSpecCode, availableStock - needCount);
List<SingleUsePackage> useList = new ArrayList<>();
SingleUsePackage sup = new SingleUsePackage();
sup.setSpecCode(bestSpecCode);
sup.setVolume(specList.stream().filter(p -> p.getSpecCode().equals(bestSpecCode)).findFirst().get().getVolume());
sup.setValidVolume(specVolMap.get(bestSpecCode));
sup.setUseCount(needCount);
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
sup.setBelongJewelryCode(condition.getJewelryList().get(0).getJewelryCode());
}
useList.add(sup);
PackResult result = new PackResult();
result.setCode(ResultCode.SUCCESS.code());
result.setMsg(ResultCode.SUCCESS.msg());
result.setUsePackageList(useList);
result.setRemainMaterialVol(0);
result.setRemainPackageStock(remainStock);
result.setTotalUsePackageCnt(needCount);
result.setSearchStateCount(1);
result.setFullLoadFlag(true);
result.setTotalCost(specCostMap.get(bestSpecCode) * needCount);
return result;
}
Map<String, Integer> startUsed = new HashMap<>();
for (String k : initStock.keySet()) startUsed.put(k, 0);
Set<String> visited = new HashSet<>();
int visitedCount = 1;
PriorityQueue<AStarItem> heap = new PriorityQueue<>(Comparator.comparingDouble(a -> a.f()));
heap.offer(new AStarItem(0, 0, 0, 0, new HashMap<>(startUsed)));
AStarItem best = null;
while (!heap.isEmpty()) {
AStarItem top = heap.poll();
String key = getStateKey(top.usedMap());
if (visited.contains(key)) continue;
visited.add(key);
visitedCount++;
if (top.g() >= needCount) {
best = top;
break;
}
if (visitedCount >= AppConfig.MAX_SEARCH_STATE) {
logger.warn("A*搜索达到最大状态限制");
break;
}
for (String specCode : validSpecCodes) {
int stockNum = initStock.get(specCode);
int usedNum = top.usedMap().get(specCode);
if (usedNum >= stockNum) continue;
int newG = top.g() + 1;
double newCost = top.cost() + specCostMap.get(specCode);
double h = (needCount - newG) * specCostMap.get(bestSpecCode) + newCost * 0.15 - specWeightMap.get(specCode) * 0.005;
double newF = newG + h;
Map<String, Integer> newUsed = new HashMap<>(top.usedMap);
newUsed.put(specCode, newUsed.get(specCode) + 1);
heap.offer(new AStarItem(newF, newG, top.loadVol() + specVolMap.get(specCode), newCost, newUsed));
}
}
if (best == null) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_ANY_LOAD_PLAN.code());
res.setMsg(ResultCode.NO_ANY_LOAD_PLAN.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>(initStock));
res.setSearchStateCount(visitedCount);
return res;
}
Map<String, Integer> remainStock = new HashMap<>();
List<SingleUsePackage> useList = new ArrayList<>();
for (Map.Entry<String, Integer> kv : initStock.entrySet()) {
String code = kv.getKey();
int totalStock = kv.getValue();
int useCnt = best.usedMap().get(code);
remainStock.put(code, totalStock - useCnt);
if (useCnt > 0) {
SingleUsePackage sup = new SingleUsePackage();
sup.setSpecCode(code);
sup.setVolume(specVolMap.get(code));
sup.setValidVolume(specVolMap.get(code));
sup.setUseCount(useCnt);
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
sup.setBelongJewelryCode(condition.getJewelryList().get(0).getJewelryCode());
}
useList.add(sup);
}
}
PackResult result = new PackResult();
result.setCode(ResultCode.SUCCESS.code());
result.setMsg(ResultCode.SUCCESS.msg());
result.setUsePackageList(useList);
result.setRemainMaterialVol(0);
result.setRemainPackageStock(remainStock);
result.setTotalUsePackageCnt(best.g());
result.setSearchStateCount(visitedCount);
result.setFullLoadFlag(true);
result.setTotalCost(best.cost());
return result;
}
private String getStateKey(Map<String, Integer> map) {
List<String> list = new ArrayList<>();
for (Map.Entry<String, Integer> e : map.entrySet()) {
list.add(e.getKey() + ":" + e.getValue());
}
Collections.sort(list);
return String.join(",", list);
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:31
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : BfsStrategy.java
* explain : 学习 类
**/
package BreadthFirst.core.strategy;
import BreadthFirst.config.AppConfig;
import BreadthFirst.core.AppLogger;
import BreadthFirst.core.enums.ResultCode;
import BreadthFirst.core.models.*;
import java.util.*;
public class BfsStrategy implements IPackStrategy {
private final AppLogger logger = AppLogger.getInstance();
private record BfsNode(double loadVol, Map<String, Integer> usedMap, double totalCost, int weightSum, int packCount) {
}
@Override
public PackResult execute(PackQueryCondition condition) {
double totalMatVol = condition.getTotalMaterialVol();
List<PackageSpec> specList = condition.getPackageSpecList();
boolean allowOver = condition.isAllowOverLoad();
int maxState = AppConfig.MAX_SEARCH_STATE;
PackConstraint cons = condition.getConstraint();
if (totalMatVol <= 0) {
PackResult res = new PackResult();
res.setCode(ResultCode.PARAM_ERROR.code());
res.setMsg(ResultCode.PARAM_ERROR.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>());
return res;
}
if (specList.isEmpty()) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_AVAILABLE_PACKAGE.code());
res.setMsg(ResultCode.NO_AVAILABLE_PACKAGE.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>());
return res;
}
Map<String, Integer> initStock = new HashMap<>();
Map<String, Double> specVolMap = new HashMap<>();
Map<String, Double> specCostMap = new HashMap<>();
Map<String, Integer> specWeightMap = new HashMap<>();
double bufferCoeff = cons != null ? cons.getBufferCoeff() : 1.0;
for (PackageSpec item : specList) {
initStock.put(item.getSpecCode(), item.getStockQty());
specVolMap.put(item.getSpecCode(), item.getValidVolume(bufferCoeff));
specCostMap.put(item.getSpecCode(), item.getUnitCost());
specWeightMap.put(item.getSpecCode(), item.getPriorityWeight());
}
int totalJewelryCount = 0;
double singleVolume = 0;
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
JewelryItem item = condition.getJewelryList().get(0);
totalJewelryCount = item.getQuantity();
singleVolume = item.getSingleVolume();
}
List<String> validSpecCodes = new ArrayList<>();
for (String code : specVolMap.keySet()) {
if (specVolMap.get(code) >= singleVolume) {
validSpecCodes.add(code);
}
}
if (validSpecCodes.isEmpty()) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_ANY_LOAD_PLAN.code());
res.setMsg(ResultCode.NO_ANY_LOAD_PLAN.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(cloneMap(initStock));
res.setSearchStateCount(1);
return res;
}
validSpecCodes.sort((a, b) -> {
int costCompare = Double.compare(specCostMap.get(a), specCostMap.get(b));
if (costCompare != 0) return costCompare;
return Integer.compare(specWeightMap.get(b), specWeightMap.get(a));
});
String bestSpecCode = validSpecCodes.get(0);
int needCount = totalJewelryCount;
int availableStock = initStock.get(bestSpecCode);
if (needCount > availableStock) {
logger.warn(String.format("【库存不足】规格%s库存%d,需要%d,尝试其他规格组合",
bestSpecCode, availableStock, needCount));
return findCombinedSolution(needCount, validSpecCodes, initStock, specVolMap, specCostMap, specWeightMap, totalMatVol);
}
Map<String, Integer> remainStock = cloneMap(initStock);
remainStock.put(bestSpecCode, availableStock - needCount);
List<SingleUsePackage> useList = new ArrayList<>();
SingleUsePackage sup = new SingleUsePackage();
sup.setSpecCode(bestSpecCode);
sup.setVolume(specList.stream().filter(p -> p.getSpecCode().equals(bestSpecCode)).findFirst().get().getVolume());
sup.setValidVolume(specVolMap.get(bestSpecCode));
sup.setUseCount(needCount);
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
sup.setBelongJewelryCode(condition.getJewelryList().get(0).getJewelryCode());
}
useList.add(sup);
PackResult result = new PackResult();
result.setCode(ResultCode.SUCCESS.code());
result.setMsg(ResultCode.SUCCESS.msg());
result.setUsePackageList(useList);
result.setRemainMaterialVol(0);
result.setRemainPackageStock(remainStock);
result.setTotalUsePackageCnt(needCount);
result.setSearchStateCount(1);
result.setFullLoadFlag(true);
result.setTotalCost(specCostMap.get(bestSpecCode) * needCount);
return result;
}
private PackResult findCombinedSolution(int needCount, List<String> validSpecCodes, Map<String, Integer> initStock,
Map<String, Double> specVolMap, Map<String, Double> specCostMap,
Map<String, Integer> specWeightMap, double totalMatVol) {
Map<String, Integer> startUsed = new HashMap<>();
for (String k : initStock.keySet()) startUsed.put(k, 0);
Set<String> visited = new HashSet<>();
int visitedCount = 1;
Queue<BfsNode> queue = new LinkedList<>();
BfsNode startNode = new BfsNode(0, cloneMap(startUsed), 0, 0, 0);
queue.offer(startNode);
visited.add(getStateKey(startUsed));
BfsNode bestNode = null;
while (!queue.isEmpty()) {
BfsNode node = queue.poll();
if (node.packCount() >= needCount) {
if (bestNode == null) {
bestNode = node;
} else {
boolean better = node.totalCost() < bestNode.totalCost()
|| (node.totalCost() == bestNode.totalCost() && node.weightSum() > bestNode.weightSum());
if (better) {
bestNode = node;
}
}
continue;
}
if (visitedCount >= AppConfig.MAX_SEARCH_STATE) {
logger.warn("搜索达到最大状态限制 " + AppConfig.MAX_SEARCH_STATE + ",终止搜索");
break;
}
for (String specCode : validSpecCodes) {
int stockNum = initStock.get(specCode);
int usedNum = node.usedMap().get(specCode);
if (usedNum >= stockNum) continue;
Map<String, Integer> newUsed = cloneMap(node.usedMap());
newUsed.put(specCode, newUsed.get(specCode) + 1);
String key = getStateKey(newUsed);
if (visited.contains(key)) continue;
visited.add(key);
visitedCount++;
BfsNode newNode = new BfsNode(
node.loadVol() + specVolMap.get(specCode),
newUsed,
node.totalCost() + specCostMap.get(specCode),
node.weightSum() + specWeightMap.get(specCode),
node.packCount() + 1
);
queue.offer(newNode);
}
}
if (bestNode == null) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_ANY_LOAD_PLAN.code());
res.setMsg(ResultCode.NO_ANY_LOAD_PLAN.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(cloneMap(initStock));
res.setSearchStateCount(visitedCount);
return res;
}
Map<String, Integer> remainStock = new HashMap<>();
List<SingleUsePackage> useList = new ArrayList<>();
for (Map.Entry<String, Integer> kv : initStock.entrySet()) {
String code = kv.getKey();
int totalStock = kv.getValue();
int useCnt = bestNode.usedMap().get(code);
remainStock.put(code, totalStock - useCnt);
if (useCnt > 0) {
SingleUsePackage sup = new SingleUsePackage();
sup.setSpecCode(code);
sup.setVolume(specVolMap.get(code));
sup.setValidVolume(specVolMap.get(code));
sup.setUseCount(useCnt);
useList.add(sup);
}
}
PackResult result = new PackResult();
result.setCode(ResultCode.SUCCESS.code());
result.setMsg(ResultCode.SUCCESS.msg());
result.setUsePackageList(useList);
result.setRemainMaterialVol(0);
result.setRemainPackageStock(remainStock);
result.setTotalUsePackageCnt(bestNode.packCount());
result.setSearchStateCount(visitedCount);
result.setFullLoadFlag(true);
result.setTotalCost(bestNode.totalCost());
return result;
}
private Map<String, Integer> cloneMap(Map<String, Integer> src) {
return new HashMap<>(src);
}
private String getStateKey(Map<String, Integer> map) {
List<String> list = new ArrayList<>();
for (Map.Entry<String, Integer> e : map.entrySet()) {
list.add(e.getKey() + ":" + e.getValue());
}
Collections.sort(list);
return String.join(",", list);
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:32
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : DfsStrategy.java
* explain : 学习 类
**/
package BreadthFirst.core.strategy;
import BreadthFirst.config.AppConfig;
import BreadthFirst.core.AppLogger;
import BreadthFirst.core.enums.ResultCode;
import BreadthFirst.core.models.*;
import java.util.*;
public class DfsStrategy implements IPackStrategy {
private final AppLogger logger = AppLogger.getInstance();
private Map<String, Double> specVolMap = new HashMap<>();
private Map<String, Double> specCostMap = new HashMap<>();
private Map<String, Integer> initStock = new HashMap<>();
private DfsNode bestNode;
private Set<String> visited = new HashSet<>();
private int visitedCnt;
private int needCount;
private record DfsNode(double loadVol, Map<String, Integer> usedMap, double totalCost, int packCnt) {
}
@Override
public PackResult execute(PackQueryCondition condition) {
double totalMatVol = condition.getTotalMaterialVol();
List<PackageSpec> specList = condition.getPackageSpecList();
PackConstraint cons = condition.getConstraint();
if (totalMatVol <= 0) {
PackResult res = new PackResult();
res.setCode(ResultCode.PARAM_ERROR.code());
res.setMsg(ResultCode.PARAM_ERROR.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>());
return res;
}
if (specList.isEmpty()) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_AVAILABLE_PACKAGE.code());
res.setMsg(ResultCode.NO_AVAILABLE_PACKAGE.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>());
return res;
}
initStock.clear();
specVolMap.clear();
specCostMap.clear();
double bufferCoeff = cons != null ? cons.getBufferCoeff() : 1.0;
for (PackageSpec item : specList) {
initStock.put(item.getSpecCode(), item.getStockQty());
specVolMap.put(item.getSpecCode(), item.getValidVolume(bufferCoeff));
specCostMap.put(item.getSpecCode(), item.getUnitCost());
}
needCount = 0;
double singleVolume = 0;
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
JewelryItem item = condition.getJewelryList().get(0);
needCount = item.getQuantity();
singleVolume = item.getSingleVolume();
}
List<String> validSpecCodes = new ArrayList<>();
for (String code : specVolMap.keySet()) {
if (specVolMap.get(code) >= singleVolume) {
validSpecCodes.add(code);
}
}
if (validSpecCodes.isEmpty()) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_ANY_LOAD_PLAN.code());
res.setMsg(ResultCode.NO_ANY_LOAD_PLAN.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>(initStock));
res.setSearchStateCount(1);
return res;
}
validSpecCodes.sort(Comparator.comparingDouble(specCostMap::get));
String bestSpecCode = validSpecCodes.get(0);
int availableStock = initStock.get(bestSpecCode);
if (needCount <= availableStock) {
Map<String, Integer> remainStock = new HashMap<>(initStock);
remainStock.put(bestSpecCode, availableStock - needCount);
List<SingleUsePackage> useList = new ArrayList<>();
SingleUsePackage sup = new SingleUsePackage();
sup.setSpecCode(bestSpecCode);
sup.setVolume(specList.stream().filter(p -> p.getSpecCode().equals(bestSpecCode)).findFirst().get().getVolume());
sup.setValidVolume(specVolMap.get(bestSpecCode));
sup.setUseCount(needCount);
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
sup.setBelongJewelryCode(condition.getJewelryList().get(0).getJewelryCode());
}
useList.add(sup);
PackResult result = new PackResult();
result.setCode(ResultCode.SUCCESS.code());
result.setMsg(ResultCode.SUCCESS.msg());
result.setUsePackageList(useList);
result.setRemainMaterialVol(0);
result.setRemainPackageStock(remainStock);
result.setTotalUsePackageCnt(needCount);
result.setSearchStateCount(1);
result.setFullLoadFlag(true);
result.setTotalCost(specCostMap.get(bestSpecCode) * needCount);
return result;
}
Map<String, Integer> startUsed = new HashMap<>();
for (String k : initStock.keySet()) startUsed.put(k, 0);
visited.clear();
visitedCnt = 0;
bestNode = null;
dfs(0, startUsed, 0, 0, validSpecCodes);
if (bestNode == null) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_ANY_LOAD_PLAN.code());
res.setMsg(ResultCode.NO_ANY_LOAD_PLAN.msg());
res.setRemainMaterialVol(totalMatVol);
res.setRemainPackageStock(new HashMap<>(initStock));
res.setSearchStateCount(visitedCnt);
return res;
}
Map<String, Integer> remainStock = new HashMap<>();
List<SingleUsePackage> useList = new ArrayList<>();
for (Map.Entry<String, Integer> kv : initStock.entrySet()) {
String code = kv.getKey();
int totalStock = kv.getValue();
int useCnt = bestNode.usedMap().get(code);
remainStock.put(code, totalStock - useCnt);
if (useCnt > 0) {
SingleUsePackage sup = new SingleUsePackage();
sup.setSpecCode(code);
sup.setVolume(specVolMap.get(code));
sup.setValidVolume(specVolMap.get(code));
sup.setUseCount(useCnt);
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
sup.setBelongJewelryCode(condition.getJewelryList().get(0).getJewelryCode());
}
useList.add(sup);
}
}
PackResult result = new PackResult();
result.setCode(ResultCode.SUCCESS.code());
result.setMsg(ResultCode.SUCCESS.msg());
result.setUsePackageList(useList);
result.setRemainMaterialVol(0);
result.setRemainPackageStock(remainStock);
result.setTotalUsePackageCnt(bestNode.packCnt());
result.setSearchStateCount(visitedCnt);
result.setFullLoadFlag(true);
result.setTotalCost(bestNode.totalCost());
return result;
}
private void dfs(double loadVol, Map<String, Integer> usedMap, double cost, int packCnt, List<String> validSpecCodes) {
if (packCnt >= needCount) {
if (bestNode == null || cost < bestNode.totalCost()) {
bestNode = new DfsNode(loadVol, new HashMap<>(usedMap), cost, packCnt);
}
return;
}
if (visitedCnt >= AppConfig.MAX_SEARCH_STATE) return;
String key = getStateKey(usedMap);
if (visited.contains(key)) return;
visited.add(key);
visitedCnt++;
for (String specCode : validSpecCodes) {
int stockNum = initStock.get(specCode);
int usedNum = usedMap.get(specCode);
if (usedNum >= stockNum) continue;
usedMap.put(specCode, usedMap.get(specCode) + 1);
dfs(loadVol + specVolMap.get(specCode), usedMap, cost + specCostMap.get(specCode), packCnt + 1, validSpecCodes);
usedMap.put(specCode, usedMap.get(specCode) - 1);
}
}
private String getStateKey(Map<String, Integer> map) {
List<String> list = new ArrayList<>();
for (Map.Entry<String, Integer> e : map.entrySet()) {
list.add(e.getKey() + ":" + e.getValue());
}
Collections.sort(list);
return String.join(",", list);
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:29
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : IPackStrategy.java
* explain : 学习 类
**/
package BreadthFirst.core.strategy;
import BreadthFirst.core.models.PackQueryCondition;
import BreadthFirst.core.models.PackResult;
public interface IPackStrategy {
PackResult execute(PackQueryCondition condition);
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:28
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : LoadStrategyType.java
* explain : 学习 类
**/
package BreadthFirst.core.strategy;
public enum LoadStrategyType {
BFS,
DFS,
ASTAR
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:30
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : AppLogger.java
* explain : 学习 类
**/
package BreadthFirst.core;
import BreadthFirst.config.AppConfig;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
public class AppLogger {
private static AppLogger instance;
private static final Object lock = new Object();
private final String logPath;
private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private AppLogger() {
AppConfig.initLogDir();
logPath = AppConfig.LOG_SAVE_PATH + File.separator + AppConfig.LOG_FILE_NAME;
}
public static AppLogger getInstance() {
if (instance == null) {
synchronized (lock) {
if (instance == null) {
instance = new AppLogger();
}
}
}
return instance;
}
private void write(String level, String message) {
String time = sdf.format(new Date());
String line = String.format("[%s] [%s] %s", time, level, message);
if (AppConfig.LOG_CONSOLE_ENABLE) {
System.out.println(line);
}
if (AppConfig.LOG_FILE_ENABLE) {
try (PrintWriter pw = new PrintWriter(new FileWriter(logPath, StandardCharsets.UTF_8), true)) {
pw.println(line);
} catch (IOException ignored) {
}
}
}
public void info(String msg) {
write("INFO", msg);
}
public void warn(String msg) {
write("WARN", msg);
}
public void error(String msg) {
write("ERROR", msg);
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:35
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : JewelryPackageService.java
* explain : 学习 类
**/
package BreadthFirst.service;
import BreadthFirst.concurrency.SafeTaskPool;
import BreadthFirst.core.AppLogger;
import BreadthFirst.core.models.*;
import BreadthFirst.core.strategy.AStarStrategy;
import BreadthFirst.core.strategy.BfsStrategy;
import BreadthFirst.core.strategy.DfsStrategy;
import BreadthFirst.core.strategy.IPackStrategy;
import BreadthFirst.core.strategy.LoadStrategyType;
import BreadthFirst.core.enums.ResultCode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JewelryPackageService {
private final AppLogger logger = AppLogger.getInstance();
public double calcJewelryTotalVolume(List<JewelryItem> list) {
double total = 0;
logger.info("=====开始计算各类首饰物料体积明细=====");
for (JewelryItem item : list) {
double vol = item.getTotalVolume();
logger.info(String.format("货号:%s | 单件体积:%.2f cm³ | 数量:%d | 品类合计:%.2f cm³",
item.getJewelryCode(), item.getSingleVolume(), item.getQuantity(), vol));
total += vol;
}
logger.info(String.format("【汇总完成】所有首饰物料理论总体积 = %.2f cm³", total));
return total;
}
public boolean checkForbidSplitConstraint(JewelryItem item, List<PackageSpec> packages, double coeff) {
double singleV = item.getSingleVolume();
for (PackageSpec pkg : packages) {
double valid = pkg.getValidVolume(coeff);
if (singleV <= valid)
return true;
}
logger.error(String.format("【约束冲突】首饰%s单件体积%.2f,无盒子可容纳,禁止拆盒模式无解",
item.getJewelryCode(), singleV));
return false;
}
public List<PackQueryCondition> splitByJewelry(PackQueryCondition origin) {
PackConstraint cons = origin.getConstraint();
if (cons == null || !cons.isForbidMixJewelry()) {
List<PackQueryCondition> list = new ArrayList<>();
list.add(origin);
return list;
}
logger.info("【启用禁止混装规则】各首饰品类独立计算包装方案");
List<PackQueryCondition> subList = new ArrayList<>();
for (JewelryItem j : origin.getJewelryList()) {
if (cons.isForbidSplitJewelry()) {
if (!checkForbidSplitConstraint(j, origin.getPackageSpecList(), cons.getBufferCoeff()))
continue;
}
PackQueryCondition subCond = new PackQueryCondition();
List<JewelryItem> subItemList = new ArrayList<>();
subItemList.add(j);
subCond.setJewelryList(subItemList);
subCond.setConstraint(cons);
subCond.setTotalMaterialVol(j.getTotalVolume());
subCond.setPackageSpecList(origin.getPackageSpecList());
subCond.setStrategyType(origin.getStrategyType());
subCond.setAllowOverLoad(origin.isAllowOverLoad());
subList.add(subCond);
}
return subList;
}
public IPackStrategy createStrategy(LoadStrategyType type) {
return switch (type) {
case BFS -> new BfsStrategy();
case DFS -> new DfsStrategy();
case ASTAR -> new AStarStrategy();
};
}
public PackResult calcSinglePlan(PackQueryCondition condition) throws Exception {
if (condition.getConstraint() != null) {
PackConstraint c = condition.getConstraint();
logger.info("=======装箱约束参数=======");
logger.info("缓冲空隙系数:" + c.getBufferCoeff());
logger.info("单盒最大首饰件数:" + c.getSingleBoxMaxQty());
logger.info("禁止不同品类混装:" + c.isForbidMixJewelry());
logger.info("禁止同品类拆盒:" + c.isForbidSplitJewelry());
}
double calcVol = 0;
if (condition.getJewelryList() != null && !condition.getJewelryList().isEmpty()) {
calcVol = calcJewelryTotalVolume(condition.getJewelryList());
condition.setTotalMaterialVol(calcVol);
}
List<PackQueryCondition> subConditions = splitByJewelry(condition);
IPackStrategy strategy = createStrategy(condition.getStrategyType());
SafeTaskPool pool = SafeTaskPool.getInstance();
List<PackResult> subResults = new ArrayList<>();
for (PackQueryCondition subCond : subConditions) {
subResults.add(pool.submit(strategy, subCond));
}
PackResult mergeResult = mergeSubResult(subResults, condition);
mergeResult.setJewelryTotalCalcVol(calcVol);
printResultLog(mergeResult);
return mergeResult;
}
public PackResult mergeSubResult(List<PackResult> subList, PackQueryCondition origin) {
List<SingleUsePackage> usePackages = new ArrayList<>();
Map<String, Integer> remainStock = new HashMap<>();
double remainMatSum = 0;
int totalSearch = 0;
double totalCostSum = 0;
boolean allSuccess = true;
for (PackageSpec pkg : origin.getPackageSpecList())
remainStock.put(pkg.getSpecCode(), pkg.getStockQty());
for (PackResult sub : subList) {
if (sub.getCode() != ResultCode.SUCCESS.code()) allSuccess = false;
remainMatSum += sub.getRemainMaterialVol();
totalSearch += sub.getSearchStateCount();
totalCostSum += sub.getTotalCost();
usePackages.addAll(sub.getUsePackageList());
for (SingleUsePackage pu : sub.getUsePackageList())
remainStock.put(pu.getSpecCode(), remainStock.get(pu.getSpecCode()) - pu.getUseCount());
}
int totalPackCnt = 0;
for (SingleUsePackage p : usePackages) totalPackCnt += p.getUseCount();
boolean fullFlag = remainMatSum <= 0.01;
if (!allSuccess) {
PackResult res = new PackResult();
res.setCode(ResultCode.NO_ANY_LOAD_PLAN.code());
res.setMsg("部分品类无法找到可行包装方案");
res.setUsePackageList(usePackages);
res.setRemainMaterialVol(Math.round(remainMatSum * 100) / 100.0);
res.setRemainPackageStock(remainStock);
res.setTotalUsePackageCnt(totalPackCnt);
res.setSearchStateCount(totalSearch);
res.setFullLoadFlag(fullFlag);
res.setTotalCost(totalCostSum);
return res;
}
PackResult res = new PackResult();
res.setCode(ResultCode.SUCCESS.code());
res.setMsg(ResultCode.SUCCESS.msg());
res.setUsePackageList(usePackages);
res.setRemainMaterialVol(Math.round(remainMatSum * 100) / 100.0);
res.setRemainPackageStock(remainStock);
res.setTotalUsePackageCnt(totalPackCnt);
res.setSearchStateCount(totalSearch);
res.setFullLoadFlag(fullFlag);
res.setTotalCost(totalCostSum);
return res;
}
public void printResultLog(PackResult res) {
logger.info("=====================配载结果=====================");
logger.info(String.format("首饰明细汇总理论总体积:%.2f cm³", res.getJewelryTotalCalcVol()));
logger.info(String.format("返回码:%d 消息:%s", res.getCode(), res.getMsg()));
logger.info("搜索遍历状态总数:" + res.getSearchStateCount());
logger.info("总共使用包装数量:" + res.getTotalUsePackageCnt());
logger.info(String.format("方案预估总成本:%.2f", res.getTotalCost()));
logger.info("物料是否完全装满:" + res.isFullLoadFlag());
logger.info(String.format("剩余未装入物料体积:%.2f cm³", res.getRemainMaterialVol()));
logger.info("本次选用包装清单:");
for (SingleUsePackage item : res.getUsePackageList()) {
logger.info(String.format(" 编码:%s 标称容积:%.2fcm³ 有效容积:%.2fcm³ 使用数量:%d 装载品类:%s",
item.getSpecCode(), item.getVolume(), item.getValidVolume(), item.getUseCount(), item.getBelongJewelryCode()));
}
logger.info("包装库存剩余情况:");
for (Map.Entry<String, Integer> kv : res.getRemainPackageStock().entrySet()) {
logger.info(String.format(" %s 剩余库存:%d", kv.getKey(), kv.getValue()));
}
logger.info("==================================================");
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:34
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : SafeTaskPool.java
* explain : 学习 类
**/
package BreadthFirst.concurrency;
import BreadthFirst.config.AppConfig;
import BreadthFirst.core.strategy.IPackStrategy;
import BreadthFirst.core.models.PackQueryCondition;
import BreadthFirst.core.models.PackResult;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class SafeTaskPool {
private static SafeTaskPool instance;
private static final Object lock = new Object();
private final ExecutorService executor;
private SafeTaskPool(int maxWorker) {
executor = Executors.newFixedThreadPool(maxWorker);
}
public static SafeTaskPool getInstance() {
if (instance == null) {
synchronized (lock) {
if (instance == null) {
instance = new SafeTaskPool(AppConfig.MAX_WORKER_THREAD);
}
}
}
return instance;
}
public PackResult submit(IPackStrategy strategy, PackQueryCondition condition) throws Exception {
Future<PackResult> future = executor.submit(() -> strategy.execute(condition));
return future.get();
}
}
/**
* encoding: utf-8
* 版权所有 2026 ©涂聚文有限公司 ®
* 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
* 描述:Breadth First Search Algorithm and Depth First Search Algorithm
* Author : geovindu,Geovin Du 涂聚文.
* IDE : IntelliJ IDEA 2024.3.6 Java 17
* # database : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
* # OS : window10
* Datetime : 2026 - 2026/7/28 - 21:36
* User : geovindu
* Product : IntelliJ IDEA
* Project : JavaAlgorithms
* File : BreadthFirstBll.java
* explain : 学习 类
**/
package Bll;
import BreadthFirst.core.AppLogger;
import BreadthFirst.core.models.JewelryItem;
import BreadthFirst.core.models.PackConstraint;
import BreadthFirst.core.models.PackQueryCondition;
import BreadthFirst.core.models.PackageSpec;
import BreadthFirst.core.strategy.LoadStrategyType;
import BreadthFirst.service.JewelryPackageService;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class BreadthFirstBll {
private static final AppLogger log = AppLogger.getInstance();
private static final JewelryPackageService service = new JewelryPackageService();
private static final Scanner scanner = new Scanner(System.in);
static double readDouble(String prompt) {
while (true) {
System.out.print(prompt);
String line = scanner.nextLine().trim();
try {
double v = Double.parseDouble(line);
if (v > 0) return v;
} catch (Exception ignored) {
}
System.out.println("输入错误,请输入大于0数字");
}
}
static int readInt(String prompt) {
while (true) {
System.out.print(prompt);
String line = scanner.nextLine().trim();
try {
int v = Integer.parseInt(line);
if (v >= 0) return v;
} catch (Exception ignored) {
}
System.out.println("输入错误,请输入非负整数");
}
}
static boolean readBool(String prompt) {
while (true) {
System.out.print(prompt + " y/n:");
String line = scanner.nextLine().trim().toLowerCase();
if ("y".equals(line)) return true;
if ("n".equals(line)) return false;
System.out.println("只能输入 y / n");
}
}
public void Demo()
{
List<JewelryItem> jewelryList = new ArrayList<>();
List<PackageSpec> pkgList = new ArrayList<>();
PackConstraint constraint = null;
while (true) {
System.out.println("\n================珠宝首饰智能包装配载系统 Java版================");
System.out.println("1. 录入首饰品类清单");
System.out.println("2. 录入包装规格(容积、成本、优先级权重、库存)");
System.out.println("3. 设置装箱约束");
System.out.println("4. BFS配载(推荐)");
System.out.println("5. DFS配载");
System.out.println("6. A*启发配载");
System.out.println("0. 退出");
System.out.print("请输入选项:");
String opt = scanner.nextLine().trim();
switch (opt) {
case "1":
jewelryList.clear();
while (true) {
System.out.print("首饰货号:");
String code = scanner.nextLine().trim();
double sv = readDouble("单件首饰体积 cm³:");
int qty = readInt("品类数量:");
JewelryItem item = new JewelryItem();
item.setJewelryCode(code);
item.setSingleVolume(sv);
item.setQuantity(qty);
jewelryList.add(item);
if (!readBool("继续录入首饰?")) break;
}
break;
case "2":
pkgList.clear();
while (true) {
System.out.print("包装编码:");
String code = scanner.nextLine().trim();
double vol = readDouble("标称容积 cm³:");
double cost = readDouble("单个包装成本:");
int weight = readInt("优先级权重(1~100):");
int stock = readInt("可用库存:");
PackageSpec pkg = new PackageSpec();
pkg.setSpecCode(code);
pkg.setVolume(vol);
pkg.setUnitCost(cost);
pkg.setPriorityWeight(weight);
pkg.setStockQty(stock);
pkgList.add(pkg);
if (!readBool("继续录入包装?")) break;
}
break;
case "3":
double bufCoeff = readDouble("缓冲空隙系数(0.7~0.95):");
int maxBoxQty = readInt("单个礼盒最大首饰件数:");
boolean forbidMix = readBool("禁止不同品类混装?");
boolean forbidSplit = readBool("禁止同一品类拆分多个盒子?");
constraint = new PackConstraint();
constraint.setBufferCoeff(bufCoeff);
constraint.setSingleBoxMaxQty(maxBoxQty);
constraint.setForbidMixJewelry(forbidMix);
constraint.setForbidSplitJewelry(forbidSplit);
log.info("装箱约束参数设置完成!");
break;
case "4":
case "5":
case "6":
if (jewelryList.isEmpty() || pkgList.isEmpty() || constraint == null) {
System.out.println("请先录入首饰、包装、装箱约束!");
break;
}
LoadStrategyType st = switch (opt) {
case "4" -> LoadStrategyType.BFS;
case "5" -> LoadStrategyType.DFS;
case "6" -> LoadStrategyType.ASTAR;
default -> LoadStrategyType.BFS;
};
try {
PackQueryCondition cond = new PackQueryCondition();
cond.setJewelryList(jewelryList);
cond.setConstraint(constraint);
cond.setPackageSpecList(pkgList);
cond.setStrategyType(st);
cond.setAllowOverLoad(false);
service.calcSinglePlan(cond);
}catch (Exception e) {
e.printStackTrace();
}
break;
case "0":
log.info("程序退出");
scanner.close();
return;
default:
System.out.println("无效选项");
break;
}
}
}
}
输出:

更多推荐


所有评论(0)