| | |
| | | int maxPaths, // 最大返回条数. 建议:100/500/2000;<=0 表示不限制(不建议) |
| | | int maxCost // 最大总代价(含拐点惩罚). <=0 表示不限制 |
| | | ) { |
| | | return allSimplePaths(map, start, end, maxDepth, maxPaths, maxCost, Collections.emptyList()); |
| | | } |
| | | |
| | | public List<List<NavigateNode>> allSimplePaths( |
| | | List<List<NavigateNode>> map, |
| | | NavigateNode start, |
| | | NavigateNode end, |
| | | int maxDepth, |
| | | int maxPaths, |
| | | int maxCost, |
| | | List<Integer> guideStationIds |
| | | ) { |
| | | List<List<NavigateNode>> results = new ArrayList<>(); |
| | | if (map == null || map.isEmpty() || map.get(0).isEmpty()) return results; |
| | | if (start == null || end == null) return results; |
| | |
| | | path.add(start); |
| | | |
| | | AtomicInteger pathCount = new AtomicInteger(0); |
| | | Map<Integer, NavigateNode> guideNodeMap = buildGuideNodeMap(map, guideStationIds); |
| | | |
| | | dfsAllSimplePaths(map, start, end, |
| | | visited, path, results, |
| | | 0, // depth |
| | | 0, // cost |
| | | maxDepth, maxPaths, maxCost, |
| | | pathCount |
| | | pathCount, |
| | | guideStationIds, |
| | | guideNodeMap |
| | | ); |
| | | |
| | | return results; |
| | |
| | | int maxDepth, |
| | | int maxPaths, |
| | | int maxCost, |
| | | AtomicInteger pathCount |
| | | AtomicInteger pathCount, |
| | | List<Integer> guideStationIds, |
| | | Map<Integer, NavigateNode> guideNodeMap |
| | | ) { |
| | | // 防爆:条数限制 |
| | | if (maxPaths > 0 && pathCount.get() >= maxPaths) return; |
| | |
| | | // 扩展邻居(严格复用你自己的可行走方向规则) |
| | | ArrayList<NavigateNode> neighbors = extend_current_node(map, current); |
| | | if (neighbors == null || neighbors.isEmpty()) return; |
| | | neighbors = sortNeighborsByGuide(current, path, neighbors, guideStationIds, guideNodeMap); |
| | | |
| | | for (NavigateNode next : neighbors) { |
| | | // 防爆:条数限制 |
| | |
| | | depth + 1, |
| | | newCost, |
| | | maxDepth, maxPaths, maxCost, |
| | | pathCount |
| | | pathCount, |
| | | guideStationIds, |
| | | guideNodeMap |
| | | ); |
| | | |
| | | // 回溯 |
| | |
| | | return n.getX() + "_" + n.getY(); |
| | | } |
| | | |
| | | private Map<Integer, NavigateNode> buildGuideNodeMap(List<List<NavigateNode>> map, List<Integer> guideStationIds) { |
| | | Map<Integer, NavigateNode> guideNodeMap = new HashMap<>(); |
| | | if (map == null || map.isEmpty() || guideStationIds == null || guideStationIds.isEmpty()) { |
| | | return guideNodeMap; |
| | | } |
| | | for (Integer stationId : guideStationIds) { |
| | | if (stationId == null || guideNodeMap.containsKey(stationId)) { |
| | | continue; |
| | | } |
| | | NavigateNode stationNode = findStationNavigateNode(map, stationId); |
| | | if (stationNode != null) { |
| | | guideNodeMap.put(stationId, stationNode); |
| | | } |
| | | } |
| | | return guideNodeMap; |
| | | } |
| | | |
| | | private ArrayList<NavigateNode> sortNeighborsByGuide(NavigateNode current, |
| | | LinkedList<NavigateNode> path, |
| | | ArrayList<NavigateNode> neighbors, |
| | | List<Integer> guideStationIds, |
| | | Map<Integer, NavigateNode> guideNodeMap) { |
| | | if (current == null || neighbors == null || neighbors.size() <= 1 |
| | | || guideStationIds == null || guideStationIds.isEmpty() |
| | | || guideNodeMap == null || guideNodeMap.isEmpty()) { |
| | | return neighbors; |
| | | } |
| | | |
| | | Integer nextGuideStationId = resolveNextGuideStationId(path, guideStationIds); |
| | | if (nextGuideStationId == null) { |
| | | return neighbors; |
| | | } |
| | | NavigateNode guideTargetNode = guideNodeMap.get(nextGuideStationId); |
| | | if (guideTargetNode == null) { |
| | | return neighbors; |
| | | } |
| | | |
| | | neighbors.sort((left, right) -> compareGuideNeighbor(current, left, right, nextGuideStationId, guideTargetNode)); |
| | | return neighbors; |
| | | } |
| | | |
| | | private Integer resolveNextGuideStationId(LinkedList<NavigateNode> path, List<Integer> guideStationIds) { |
| | | if (path == null || path.isEmpty() || guideStationIds == null || guideStationIds.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | int cursor = 0; |
| | | Set<Integer> seen = new HashSet<>(); |
| | | for (NavigateNode node : path) { |
| | | Integer stationId = extractStationId(node); |
| | | if (stationId == null || !seen.add(stationId)) { |
| | | continue; |
| | | } |
| | | if (cursor < guideStationIds.size() && stationId.equals(guideStationIds.get(cursor))) { |
| | | cursor++; |
| | | } |
| | | } |
| | | if (cursor >= guideStationIds.size()) { |
| | | return null; |
| | | } |
| | | return guideStationIds.get(cursor); |
| | | } |
| | | |
| | | private int compareGuideNeighbor(NavigateNode current, |
| | | NavigateNode left, |
| | | NavigateNode right, |
| | | Integer nextGuideStationId, |
| | | NavigateNode guideTargetNode) { |
| | | int leftDirect = isGuideStation(left, nextGuideStationId) ? 0 : 1; |
| | | int rightDirect = isGuideStation(right, nextGuideStationId) ? 0 : 1; |
| | | if (leftDirect != rightDirect) { |
| | | return Integer.compare(leftDirect, rightDirect); |
| | | } |
| | | |
| | | int leftDistance = calcNodeCost(left, guideTargetNode); |
| | | int rightDistance = calcNodeCost(right, guideTargetNode); |
| | | if (leftDistance != rightDistance) { |
| | | return Integer.compare(leftDistance, rightDistance); |
| | | } |
| | | |
| | | int leftTurnCost = calcNodeExtraCost(current, left, guideTargetNode); |
| | | int rightTurnCost = calcNodeExtraCost(current, right, guideTargetNode); |
| | | if (leftTurnCost != rightTurnCost) { |
| | | return Integer.compare(leftTurnCost, rightTurnCost); |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | private boolean isGuideStation(NavigateNode node, Integer stationId) { |
| | | Integer nodeStationId = extractStationId(node); |
| | | return nodeStationId != null && nodeStationId.equals(stationId); |
| | | } |
| | | |
| | | private Integer extractStationId(NavigateNode node) { |
| | | if (node == null || !"devp".equals(node.getNodeType())) { |
| | | return null; |
| | | } |
| | | try { |
| | | JSONObject valueObj = JSON.parseObject(node.getNodeValue()); |
| | | return valueObj == null ? null : valueObj.getInteger("stationId"); |
| | | } catch (Exception ignore) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | public ArrayList<NavigateNode> extend_current_node(List<List<NavigateNode>> map, NavigateNode current_node) { |
| | | //获取当前结点的x, y |
| | | int x = current_node.getX(); |