SinglePattern

 
package org.springblade.schedulemanagement.utils; import org.apache.commons.collections4.CollectionUtils; import org.springblade.scheduleManagementservice.entity.SteelOrder; import org.springblade.scheduleManagementservice.entity.CuttingSchedulePlan; import org.springblade.scheduleManagementservice.entity.CuttingSchedulePlanRef; import org.springblade.scheduleManagementservice.vo.CuttingPatternVO; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; public class CuttingPatternByUtils { private static final int MAX_TYPES_PER_CUT = 3; // 每种方案最多3种类型 private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP; private static final int MAX_CUTTING_ORDERS = 3; // 最大切割状态订单数 private static final int BATCH_SIZE = 10; // 每批次处理的订单数量 public static void main(String[] args) { Map<String, SteelOrder> orders = new LinkedHashMap<>(); orders.put("X19260061", new SteelOrder("X19260061", new BigDecimal("474.5"), 102, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X19260021", new SteelOrder("X19260021", new BigDecimal("407"), 200, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X25250841", new SteelOrder("X25250841", new BigDecimal("396"), 345, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20200921", new SteelOrder("X20200921", new BigDecimal("438.5"), 243, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20201321", new SteelOrder("X20201321", new BigDecimal("538"), 202, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X26264181", new SteelOrder("X26264181", new BigDecimal("487"), 345, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20200861", new SteelOrder("X20200861", new BigDecimal("474.5"), 102, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20201061", new SteelOrder("X20201061", new BigDecimal("407"), 200, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X18180191", new SteelOrder("X18180191", new BigDecimal("396"), 345, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20200811", new SteelOrder("X20200811", new BigDecimal("438.5"), 243, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20201021", new SteelOrder("X20201021", new BigDecimal("538"), 202, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X19190071", new SteelOrder("X19190071", new BigDecimal("487"), 345, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X19192041", new SteelOrder("X19192041", new BigDecimal("474.5"), 102, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20201011", new SteelOrder("X20201011", new BigDecimal("407"), 200, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20190121", new SteelOrder("X20190121", new BigDecimal("396"), 345, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20201761", new SteelOrder("X20201761", new BigDecimal("438.5"), 243, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20201001", new SteelOrder("X20201001", new BigDecimal("538"), 202, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X19191791", new SteelOrder("X19191791", new BigDecimal("487"), 345, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20202141", new SteelOrder("X20202141", new BigDecimal("474.5"), 102, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X20200891", new SteelOrder("X20200891", new BigDecimal("407"), 200, "", "精拉料/GA2040222/Φ22/40Cr", "22")); orders.put("X19260031", new SteelOrder("X19260031", new BigDecimal("396"), 345, "", "精拉料/GA2040222/Φ22/40Cr", "22")); List<CuttingPatternVO> cuttingPattern = getCuttingPattern(new BigDecimal("6000"), new BigDecimal("3"), new BigDecimal("0"), 0, orders); System.out.println("----------------------------------------"); } public static List<CuttingPatternVO> getCuttingPattern(BigDecimal STANDARD_RAW_MATERIAL_LENGTH, BigDecimal CUTTING_LOSS, BigDecimal REMAINING_RAW_MATERIAL_LENGTH, int MAX_REMAINING_MATERIALS, Map<String, org.springblade.scheduleManagementservice.entity.SteelOrder> orders) { List<CuttingPatternVO> cuttingPatternVOS = new ArrayList<>(); List<SteelOrder> remainingOrders = new ArrayList<>(orders.values()); // 复制原始订单列表 List<SteelOrder> matchedOrders = new ArrayList<>();// 存储匹配到的订单 //剩余余料 int remainMaterials = MAX_REMAINING_MATERIALS; while (!remainingOrders.isEmpty()) { // 取出当前批次的订单(10个或剩余的所有订单) int batchSize = Math.min(BATCH_SIZE, remainingOrders.size()); List<SteelOrder> currentBatch = new ArrayList<>(remainingOrders.subList(0, batchSize)); remainingOrders = remainingOrders.subList(batchSize, remainingOrders.size()); // 更新剩余订单列表 // 将之前匹配的订单添加到当前批次的最前面 if (!matchedOrders.isEmpty()) { currentBatch.addAll(0, matchedOrders); matchedOrders.clear(); } // Map<String, SteelOrder> maps2 = currentBatch.stream().collect // // (Collectors.toMap(SteelOrder::getType, Function.identity())); // Map<String, SteelOrder> maps2 = currentBatch.stream() .collect(Collectors.toMap( SteelOrder::getType, // key生成器 Function.identity(), // value生成器 (existing, replacement) -> existing, // 解决key冲突的策略(保留原有值) LinkedHashMap::new // 指定Map实现类为LinkedHashMap,保持插入顺序 )); // 处理当前批次,生成切割方案 List<CuttingPatternVO> batchPatterns = processBatch(STANDARD_RAW_MATERIAL_LENGTH, CUTTING_LOSS, REMAINING_RAW_MATERIAL_LENGTH, remainMaterials, maps2); // 检查每个切割方案的废料,尝试从剩余订单中匹配 for (CuttingPatternVO pattern : batchPatterns) { BigDecimal remainder = pattern.getCuttingSchedulePlan().getWasteLength(); if (remainder.compareTo(BigDecimal.ZERO) > 0) { // 从剩余订单中查找可匹配的订单 if (CollectionUtils.isNotEmpty(matchedOrders)) { for (Iterator<SteelOrder> it = matchedOrders.iterator(); it.hasNext(); ) { SteelOrder order = it.next(); if (order.getQuantity() > 0 && order.getLength().add(CUTTING_LOSS).compareTo(remainder) <= 0) { // 计算可以添加的数量 int addableQuantity = Math.min( order.getQuantity(), remainder.divide(order.getLength().add(CUTTING_LOSS), 0, RoundingMode.FLOOR).intValue() ); if (addableQuantity > 0) { // 更新切割方案 CuttingSchedulePlanRef cuttingSchedulePlanRef = new CuttingSchedulePlanRef(); cuttingSchedulePlanRef.setModel(order.getType()); cuttingSchedulePlanRef.setSingleNum(addableQuantity); cuttingSchedulePlanRef.setLength(order.getLength()); cuttingSchedulePlanRef.setTotalNum(pattern.getCuttingSchedulePlan().getNum() * addableQuantity); List<CuttingSchedulePlanRef> cuttingSchedulePlanRefs = pattern.getCuttingSchedulePlanRefs(); cuttingSchedulePlanRefs.add(cuttingSchedulePlanRef); pattern.setCuttingSchedulePlanRefs(cuttingSchedulePlanRefs); // 更新剩余废料 remainder = remainder.subtract( order.getLength().multiply(BigDecimal.valueOf(addableQuantity)) .add(CUTTING_LOSS.multiply(BigDecimal.valueOf(addableQuantity))) ); pattern.getCuttingSchedulePlan().setWasteLength(remainder); // 更新订单数量 order.setQuantity(order.getQuantity() - pattern.getCuttingSchedulePlan().getNum() * addableQuantity); if (order.getQuantity() == 0) { remainingOrders.remove(order); } // 如果废料已用完,退出循环 if (remainder.compareTo(BigDecimal.ZERO) <= 0) { break; } } } } } else { for (Iterator<SteelOrder> it = remainingOrders.iterator(); it.hasNext(); ) { SteelOrder order = it.next(); if (order.getQuantity() > 0 && order.getLength().add(CUTTING_LOSS).compareTo(remainder) <= 0) { // 计算可以添加的数量 int addableQuantity = Math.min( order.getQuantity(), remainder.divide(order.getLength().add(CUTTING_LOSS), 0, RoundingMode.FLOOR).intValue() ); if (addableQuantity > 0) { // 更新切割方案 CuttingSchedulePlanRef cuttingSchedulePlanRef = new CuttingSchedulePlanRef(); cuttingSchedulePlanRef.setModel(order.getType()); cuttingSchedulePlanRef.setSingleNum(addableQuantity); cuttingSchedulePlanRef.setLength(order.getLength()); cuttingSchedulePlanRef.setTotalNum(pattern.getCuttingSchedulePlan().getNum() * addableQuantity); List<CuttingSchedulePlanRef> cuttingSchedulePlanRefs = pattern.getCuttingSchedulePlanRefs(); cuttingSchedulePlanRefs.add(cuttingSchedulePlanRef); pattern.setCuttingSchedulePlanRefs(cuttingSchedulePlanRefs); // 更新剩余废料 remainder = remainder.subtract( order.getLength().multiply(BigDecimal.valueOf(addableQuantity)) .add(CUTTING_LOSS.multiply(BigDecimal.valueOf(addableQuantity))) ); pattern.getCuttingSchedulePlan().setWasteLength(remainder); // 更新订单数量 order.setQuantity(order.getQuantity() - pattern.getCuttingSchedulePlan().getNum() * addableQuantity); // 记录匹配到的订单 if (order.getQuantity() > 0) { matchedOrders.add(order); } // 从剩余订单列表中移除(无论数量是否为0) it.remove(); // 如果废料已用完,退出循环 if (remainder.compareTo(BigDecimal.ZERO) <= 0) { break; } } } } } } if (pattern.getCuttingSchedulePlan().getMaterialType().equals("余料")) { remainMaterials = remainMaterials - pattern.getCuttingSchedulePlan().getNum(); } } cuttingPatternVOS.addAll(batchPatterns); // 将匹配的订单添加到剩余订单列表的最前面 if (!matchedOrders.isEmpty()) { remainingOrders.addAll(0, matchedOrders); matchedOrders.clear(); } } return cuttingPatternVOS; } private static List<CuttingPatternVO> processBatch(BigDecimal STANDARD_RAW_MATERIAL_LENGTH, BigDecimal CUTTING_LOSS, BigDecimal REMAINING_RAW_MATERIAL_LENGTH, int MAX_REMAINING_MATERIALS, Map<String, org.springblade.scheduleManagementservice.entity.SteelOrder> orders) { List<CuttingPatternVO> cuttingPatternVOS = new ArrayList<>(); Map<String, Integer> completionPatterns = new HashMap<>(); // 生成所有可能的切割方案(针对两种原材料长度) List<CuttingPattern> remainingPatterns = generateAllPatterns(orders, REMAINING_RAW_MATERIAL_LENGTH, CUTTING_LOSS, STANDARD_RAW_MATERIAL_LENGTH); List<CuttingPattern> standardPatterns = generateAllPatterns(orders, STANDARD_RAW_MATERIAL_LENGTH, CUTTING_LOSS, STANDARD_RAW_MATERIAL_LENGTH); // 优先使用剩余原材料,再使用标准原材料 List<UsedPattern> usedPatterns = solveByPriorityGreedy( remainingPatterns, standardPatterns, orders, completionPatterns, MAX_REMAINING_MATERIALS, STANDARD_RAW_MATERIAL_LENGTH, REMAINING_RAW_MATERIAL_LENGTH, CUTTING_LOSS); // 输出结果 printResults(usedPatterns, orders, completionPatterns, cuttingPatternVOS); // 释放不再使用的对象 remainingPatterns = null; standardPatterns = null; usedPatterns = null; completionPatterns = null; return cuttingPatternVOS; } // 生成所有可能的切割方案,考虑切割损耗 private static List<CuttingPattern> generateAllPatterns(Map<String, SteelOrder> orders, BigDecimal materialLength, BigDecimal CUTTING_LOSS, BigDecimal STANDARD_RAW_MATERIAL_LENGTH) { List<CuttingPattern> patterns = new ArrayList<>(); List<String> keys = new ArrayList<>(orders.keySet()); for (int r = 1; r <= MAX_TYPES_PER_CUT; r++) { generateCombinations(keys, r, combination -> { // 提前剪枝:计算组合的最小总长度,如果超过原材料长度,直接跳过 BigDecimal minTotalLength = calculateMinTotalLength(combination, orders, CUTTING_LOSS); if (minTotalLength.compareTo(materialLength) > 0) { return; } if (!materialLength.equals(STANDARD_RAW_MATERIAL_LENGTH)) { // 处理剩余原材料,检查减去切割损耗后是否足够 boolean canUse = false; for (String key : combination) { SteelOrder order = orders.get(key); if (materialLength.subtract(CUTTING_LOSS).compareTo(order.length) >= 0) { canUse = true; break; } } if (canUse) { generatePatternsForCombination(combination, orders, patterns, materialLength, CUTTING_LOSS, STANDARD_RAW_MATERIAL_LENGTH); } } else { // 处理标准原材料,正常生成方案 generatePatternsForCombination(combination, orders, patterns, materialLength, CUTTING_LOSS, STANDARD_RAW_MATERIAL_LENGTH); } }); } // 新增:按废料量升序,再按利用率((材料长度-废料)/材料长度)降序排序 patterns.sort(Comparator.comparing((CuttingPattern p) -> p.remainder) .thenComparing(p -> { BigDecimal usedLength = materialLength.subtract(p.remainder); return usedLength.divide(materialLength, 4, ROUNDING_MODE).negate(); // 利用率高的排前面 })); return patterns; } // 计算组合的最小总长度 private static BigDecimal calculateMinTotalLength(List<String> combination, Map<String, SteelOrder> orders, BigDecimal CUTTING_LOSS) { // BigDecimal minTotalLength = BigDecimal.ZERO; // for (String key : combination) { // SteelOrder order = orders.get(key); // minTotalLength = minTotalLength.add(order.length); // } // if (combination.size() > 0) { // minTotalLength = minTotalLength.add(CUTTING_LOSS.multiply(BigDecimal.valueOf(combination.size() - 1))); // } // return minTotalLength; BigDecimal minTotalLength = BigDecimal.ZERO; for (String key : combination) { SteelOrder order = orders.get(key); minTotalLength = minTotalLength.add(order.length); } // 原逻辑:仅计算1次切割损耗(组合大小-1) // 优化:考虑最少1段的情况(避免组合中单个长零件被误判) int cutTimes = Math.max(combination.size() - 1, 1); minTotalLength = minTotalLength.add(CUTTING_LOSS.multiply(BigDecimal.valueOf(cutTimes))); return minTotalLength; } // 生成指定组合的所有可能切割方案,考虑切割损耗 private static void generatePatternsForCombination( List<String> combination, Map<String, SteelOrder> orders, List<CuttingPattern> patterns, BigDecimal materialLength, BigDecimal CUTTING_LOSS, BigDecimal STANDARD_RAW_MATERIAL_LENGTH) { List<BigDecimal> lengths = new ArrayList<>(); for (String key : combination) { lengths.add(orders.get(key).length); } // 计算每种类型的最大可能数量,考虑切割损耗 List<Integer> maxCounts = new ArrayList<>(); for (BigDecimal length : lengths) { int maxCount = 0; BigDecimal totalLength = BigDecimal.ZERO; while (true) { maxCount++; // 总长度 = 钢材长度 * 数量 + 切割损耗 * (数量 - 1) totalLength = length.multiply(BigDecimal.valueOf(maxCount)) .add(CUTTING_LOSS.multiply(BigDecimal.valueOf(maxCount - 1))); if (totalLength.compareTo(materialLength) > 0) { maxCount--; break; } } maxCounts.add(maxCount); } // 生成所有可能的数量组合 List<int[]> countCombinations = new ArrayList<>(); generateCountCombinations(maxCounts, countCombinations); // 检查每个组合的总长度是否不超过原材料长度,考虑切割损耗 for (int[] counts : countCombinations) { int totalPieces = 0; for (int count : counts) { totalPieces += count; } if (totalPieces == 0) continue; // 跳过没有钢材的组合 BigDecimal totalLength = BigDecimal.ZERO; for (int i = 0; i < counts.length; i++) { totalLength = totalLength.add(lengths.get(i).multiply(BigDecimal.valueOf(counts[i]))); } // 添加切割损耗 totalLength = totalLength.add(CUTTING_LOSS.multiply(BigDecimal.valueOf(totalPieces - 1))); if (totalLength.compareTo(materialLength) <= 0) { Map<String, Integer> patternMap = new LinkedHashMap<>(); for (int i = 0; i < combination.size(); i++) { if (counts[i] > 0) { patternMap.put(combination.get(i), counts[i]); } } patterns.add(new CuttingPattern( patternMap, materialLength.subtract(totalLength), materialLength.equals(STANDARD_RAW_MATERIAL_LENGTH))); } } } // 生成所有可能的数量组合 private static void generateCountCombinations(List<Integer> maxCounts, List<int[]> result) { int[] current = new int[maxCounts.size()]; generateCountCombinationsRecursive(maxCounts, current, 0, result); } private static void generateCountCombinationsRecursive( List<Integer> maxCounts, int[] current, int index, List<int[]> result) { if (index == maxCounts.size()) { boolean hasPieces = false; for (int count : current) { if (count > 0) { hasPieces = true; break; } } if (hasPieces) { result.add(Arrays.copyOf(current, current.length)); } return; } // for (int i = 0; i <= maxCounts.get(index); i++) { // current[index] = i; // generateCountCombinationsRecursive(maxCounts, current, index + 1, result); // } // 原有是从0到max,改为从max到0,优先生成大数量组合 for (int i = maxCounts.get(index); i >= 0; i--) { current[index] = i; generateCountCombinationsRecursive(maxCounts, current, index + 1, result); } } // 生成组合的辅助方法 private static void generateCombinations(List<String> list, int r, CombinationCallback callback) { if (r == 0) { callback.process(Collections.emptyList()); // 生成空组合 return; } if (list.size() < r) { // 无法生成组合,直接返回或抛出异常 return; } int[] indices = new int[r]; for (int i = 0; i < r; i++) { indices[i] = i; } callback.process(getCombination(list, indices)); while (true) { int i = r - 1; while (i >= 0 && indices[i] == list.size() - r + i) { i--; } if (i < 0) { break; } indices[i]++; for (int j = i + 1; j < r; j++) { indices[j] = indices[j - 1] + 1; } callback.process(getCombination(list, indices)); } } private static List<String> getCombination(List<String> list, int[] indices) { List<String> combination = new ArrayList<>(); for (int index : indices) { if (index >= 0 && index < list.size()) { combination.add(list.get(index)); } } return combination; } // 优先级贪心算法求解,优先处理已在切割状态的订单,优先使用剩余原材料 private static List<UsedPattern> solveByPriorityGreedy( List<CuttingPattern> remainingPatterns, List<CuttingPattern> standardPatterns, Map<String, SteelOrder> orders, Map<String, Integer> completionPatterns, int MAX_REMAINING_MATERIALS, BigDecimal STANDARD_RAW_MATERIAL_LENGTH, BigDecimal REMAINING_RAW_MATERIAL_LENGTH, BigDecimal CUTTING_LOSS) { // 检查剩余原材料长度减去切割损耗后是否比所有订单长度都小 boolean canUseRemaining = false; for (SteelOrder order : orders.values()) { if (REMAINING_RAW_MATERIAL_LENGTH.subtract(CUTTING_LOSS).compareTo(order.length) >= 0) { canUseRemaining = true; break; } } if (!canUseRemaining) { MAX_REMAINING_MATERIALS = 0; // 不能使用剩余原材料,将剩余原材料数量置为0 } // 复制订单数据以便修改 Map<String, SteelOrder> remainingOrders = new LinkedHashMap<>(); for (Map.Entry<String, SteelOrder> entry : orders.entrySet()) { remainingOrders.put(entry.getKey(), new SteelOrder( entry.getValue().type, entry.getValue().length, entry.getValue().quantity, entry.getValue().materialType, entry.getValue().description, entry.getValue().specifications)); } // 记录当前处于切割状态的订单 Set<String> cuttingOrders = new HashSet<>(); List<UsedPattern> usedPatterns = new ArrayList<>(); int remainingMaterialsUsed = 0; // 已使用的剩余原材料数量 // int standardMaterialsUsed = 0; // 已使用的标准原材料数量 // 按余料升序排序,余料相同则按类型数降序排序 List<CuttingPattern> allPatterns = new ArrayList<>(); allPatterns.addAll(remainingPatterns); allPatterns.addAll(standardPatterns); // allPatterns.sort(Comparator.comparing((CuttingPattern p) -> p.remainder) // .thenComparing(p -> -calculateTotalPieces(p.quantities))); // 原有排序逻辑增强 allPatterns.sort(Comparator.comparing((CuttingPattern p) -> p.remainder) .thenComparing(p -> -calculateTotalPieces(p.quantities)) // 新增:优先包含小长度订单的方案(小长度更易填充余料) .thenComparing(p -> { BigDecimal minLength = BigDecimal.valueOf(Integer.MAX_VALUE); for (String type : p.quantities.keySet()) { BigDecimal len = orders.get(type).length; if (len.compareTo(minLength) < 0) { minLength = len; } } return minLength; // 小长度在前 })); int currentPatternNumber = 0; while (hasRemainingOrders(remainingOrders)) { currentPatternNumber++; boolean patternUsed = false; // 尝试优先使用剩余原材料的模式 for (CuttingPattern pattern : allPatterns) { // 如果是标准原材料模式,但剩余原材料还没用完,则跳过 if (pattern.isStandard && remainingMaterialsUsed < MAX_REMAINING_MATERIALS) { continue; } // 检查该模式是否包含任何已在切割状态的订单 boolean containsCuttingOrder = false; for (String type : pattern.quantities.keySet()) { if (cuttingOrders.contains(type)) { containsCuttingOrder = true; break; } } // 如果模式不包含任何已在切割状态的订单,且切割状态订单数已满,则跳过 if (!containsCuttingOrder && cuttingOrders.size() >= MAX_CUTTING_ORDERS) { continue; } // 检查该模式是否还能满足任何剩余需求 boolean canUse = false; for (Map.Entry<String, Integer> entry : pattern.quantities.entrySet()) { String type = entry.getKey(); int needed = remainingOrders.get(type).quantity; if (needed > 0 && entry.getValue() > 0) { canUse = true; break; } } if (!canUse) { continue; } // 计算该模式可以使用的最大次数 int maxUses = Integer.MAX_VALUE; for (Map.Entry<String, Integer> entry : pattern.quantities.entrySet()) { String type = entry.getKey(); int available = remainingOrders.get(type).quantity; int neededPerUse = entry.getValue(); if (neededPerUse > 0) { int possibleUses = available / neededPerUse; if (possibleUses < maxUses) { maxUses = possibleUses; } } } // 限制使用次数,避免超出原材料数量 if (pattern.isStandard) { maxUses = Math.min(maxUses, Integer.MAX_VALUE); // 标准原材料无数量限制 } else { int remainingMaterialsLeft = MAX_REMAINING_MATERIALS - remainingMaterialsUsed; maxUses = Math.min(maxUses, remainingMaterialsLeft); } if (maxUses > 0) { // 检查使用此模式后,是否会导致超过最大切割状态订单数 Set<String> newCuttingOrders = new HashSet<>(cuttingOrders); for (String type : pattern.quantities.keySet()) { if (remainingOrders.get(type).quantity > 0) { newCuttingOrders.add(type); } } if (newCuttingOrders.size() > MAX_CUTTING_ORDERS) { continue; } // 使用该模式 usedPatterns.add(new UsedPattern(pattern, maxUses)); if (pattern.isStandard) { } else { remainingMaterialsUsed += maxUses; } // 更新剩余需求并检查是否有订单完成 for (Map.Entry<String, Integer> entry : pattern.quantities.entrySet()) { String type = entry.getKey(); int used = entry.getValue() * maxUses; remainingOrders.get(type).quantity -= used; // 检查订单是否完成 if (remainingOrders.get(type).quantity == 0 && !completionPatterns.containsKey(type)) { completionPatterns.put(type, currentPatternNumber); } } // 更新切割状态订单 cuttingOrders = newCuttingOrders; // 移除已完成的切割状态订单 Iterator<String> it = cuttingOrders.iterator(); while (it.hasNext()) { String type = it.next(); if (remainingOrders.get(type).quantity == 0) { it.remove(); } } patternUsed = true; break; } } if (!patternUsed) { // 如果没有可用的模式,尝试单独切割剩余需求量最大的类型 String maxType = findMaxRemainingType(remainingOrders); if (maxType != null) { SteelOrder order = remainingOrders.get(maxType); // 优先使用剩余原材料 boolean useStandard = remainingMaterialsUsed >= MAX_REMAINING_MATERIALS; BigDecimal materialLength = useStandard ? STANDARD_RAW_MATERIAL_LENGTH : REMAINING_RAW_MATERIAL_LENGTH; // 新增:计算单类型最大可切割数量(减少废料) int maxNum = 0; for (int num = 1; ; num++) { BigDecimal totalLoss = CUTTING_LOSS.multiply(BigDecimal.valueOf(num - 1)); // n个工件有n-1次切割 BigDecimal totalLength = order.length.multiply(BigDecimal.valueOf(num)).add(totalLoss); if (totalLength.compareTo(materialLength) > 0) { maxNum = num - 1; break; } } if (maxNum == 0) maxNum = 1; // 至少切1个 // 创建一个只切割该类型的模式,考虑切割损耗 Map<String, Integer> singlePatternMap = new LinkedHashMap<>(); singlePatternMap.put(maxType, maxNum); CuttingPattern singlePattern = new CuttingPattern( singlePatternMap, materialLength.subtract(order.length.multiply(BigDecimal.valueOf(maxNum)).add(CUTTING_LOSS.multiply(BigDecimal.valueOf(maxNum - 1)))), useStandard ); // 使用该模式一次 usedPatterns.add(new UsedPattern(singlePattern, 1)); if (useStandard) { // standardMaterialsUsed++; } else { remainingMaterialsUsed++; } order.quantity--; // 检查订单是否完成 if (order.quantity == 0 && !completionPatterns.containsKey(maxType)) { completionPatterns.put(maxType, currentPatternNumber); } // 更新切割状态订单 if (order.quantity > 0) { cuttingOrders.add(maxType); } else { cuttingOrders.remove(maxType); } patternUsed = true; } if (!patternUsed) { // 如果还是没有可用的模式,说明算法遇到了问题 break; } } } // 释放大型对象 remainingPatterns = null; standardPatterns = null; remainingOrders = null; return usedPatterns; } // 计算方案的总钢材数量 private static int calculateTotalPieces(Map<String, Integer> quantities) { int totalPieces = 0; for (int quantity : quantities.values()) { totalPieces += quantity; } return totalPieces; } // 查找剩余需求量最大的类型 private static String findMaxRemainingType(Map<String, SteelOrder> orders) { String maxType = null; int maxQuantity = 0; for (Map.Entry<String, SteelOrder> entry : orders.entrySet()) { if (entry.getValue().quantity > maxQuantity) { maxQuantity = entry.getValue().quantity; maxType = entry.getKey(); } } return maxType; } // 检查是否还有剩余订单 private static boolean hasRemainingOrders(Map<String, SteelOrder> orders) { for (SteelOrder order : orders.values()) { if (order.quantity > 0) { return true; } } return false; } // 输出结果 private static void printResults( List<org.springblade.schedulemanagement.utils.CuttingPatternByUtils.UsedPattern> usedPatterns, Map<String, SteelOrder> originalOrders, Map<String, Integer> completionPatterns, List<CuttingPatternVO> cuttingPatternVOS) { // int totalRemainingMaterials = 0; // int totalStandardMaterials = 0; BigDecimal totalRemainder = BigDecimal.ZERO; int patternNumber = 1; for (org.springblade.schedulemanagement.utils.CuttingPatternByUtils.UsedPattern usedPattern : usedPatterns) { org.springblade.schedulemanagement.utils.CuttingPatternByUtils.CuttingPattern pattern = usedPattern.pattern; int uses = usedPattern.uses; // if (pattern.isStandard) { // totalStandardMaterials += uses; // } else { // totalRemainingMaterials += uses; // } totalRemainder = totalRemainder.add(pattern.remainder.multiply(BigDecimal.valueOf(uses))); CuttingPatternVO cuttingPatternVO = new CuttingPatternVO(); CuttingSchedulePlan cuttingSchedulePlan = new CuttingSchedulePlan(); List<CuttingSchedulePlanRef> cuttingSchedulePlanRefs = new ArrayList<>(); for (Map.Entry<String, Integer> entry : pattern.quantities.entrySet()) { String type = entry.getKey(); int quantity = entry.getValue(); SteelOrder order = originalOrders.get(type); cuttingSchedulePlan.setMaterialType(pattern.isStandard ? "" : "余料"); cuttingSchedulePlan.setDescription(order.description); cuttingSchedulePlan.setSpecifications(order.specifications); CuttingSchedulePlanRef cuttingSchedulePlanRef = new CuttingSchedulePlanRef(); cuttingSchedulePlanRef.setModel(type); cuttingSchedulePlanRef.setSingleNum(quantity); cuttingSchedulePlanRef.setLength(order.length); cuttingSchedulePlanRef.setTotalNum(uses * quantity); cuttingSchedulePlanRefs.add(cuttingSchedulePlanRef); } String OrderCompletionDetails = ""; // 检查该方案是否完成了任何订单 for (String type : pattern.quantities.keySet()) { if (completionPatterns.getOrDefault(type, -1) == patternNumber) { //该芯轴编号的订单已完成 OrderCompletionDetails = OrderCompletionDetails + type + ","; } } patternNumber++; if (!OrderCompletionDetails.equals("")) { OrderCompletionDetails = OrderCompletionDetails.substring(0, OrderCompletionDetails.length() - 1); } cuttingSchedulePlan.setOrderCompletionDetails(OrderCompletionDetails); cuttingSchedulePlan.setNum(uses); cuttingSchedulePlan.setWasteLength(pattern.remainder); cuttingPatternVO.setCuttingSchedulePlan(cuttingSchedulePlan); cuttingPatternVO.setCuttingSchedulePlanRefs(cuttingSchedulePlanRefs); cuttingPatternVOS.add(cuttingPatternVO); } } // 切割方案类 static class CuttingPattern { Map<String, Integer> quantities; BigDecimal remainder; boolean isStandard; // 是否为标准原材料 public CuttingPattern(Map<String, Integer> quantities, BigDecimal remainder, boolean isStandard) { this.quantities = quantities; this.remainder = remainder.setScale(1, ROUNDING_MODE); this.isStandard = isStandard; } } // 已使用的切割方案类 static class UsedPattern { CuttingPattern pattern; int uses; public UsedPattern(CuttingPattern pattern, int uses) { this.pattern = pattern; this.uses = uses; } } // 组合回调接口 interface CombinationCallback { void process(List<String> combination); } } 怎么优化,让废料长度变的更小
08-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值