Dijkstra + A_Star 解决指定起点终点的第k长路径

例题链接:

0蓝桥王国2 - 蓝桥云课

先展示代码:
 

package daily_Test.test0422;



//样例输入

import java.util.*;

//3 4
//        1 3 9
//        1 2 3
//        1 2 1
//        2 3 2
//        1 3 1
public class DijkstraAndA_Star {
    static List<int[]>[] lists;
    static List<int[]>[] lists2;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        lists = new List[n + 1];
        lists2 = new List[n + 1];

        for (int i = 0; i <= n; i++) {
            lists[i] = new ArrayList<>();
            lists2[i] = new ArrayList<>();
        }
        for (int i = 0; i < m; i++) {
            int o1 = sc.nextInt();
            int o2 = sc.nextInt();
            int len = sc.nextInt();
            lists[o2].add(new int[]{o1, len});
            lists2[o1].add(new int[]{o2,len});
        }

        int a = sc.nextInt();
        int e = sc.nextInt();
        int k = sc.nextInt();
        int[] res = Dijkstra(e,lists);
        int ans = A_Star(lists2,a,e,k,res);
        System.out.println(ans);
    }

    private static int A_Star(List<int[]>[] lists2, int start, int end, int k, int[] expect) {
        PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2)->{
            return o1[0] - o2[0];
        });
        int count = 0;
         pq.offer(new int[]{expect[start],start,0});
         while (!pq.isEmpty()){
             int[] a = pq.poll();
             int e = a[0],node = a[1],l = a[2];
             if(node == end){
                 count++;
                 if(count == k){
                     return node;
                 }
             }
             for(int[] next:lists2[node]){
                 pq.offer(new int[]{e+expect[next[0]]+next[1],next[0],l+next[1]});
             }
         }
         return -1;
    }

    private static int[] Dijkstra(int target, List<int[]>[] lists) {
        int[] arr = new int[lists.length+1];
        Arrays.fill(arr,Integer.MAX_VALUE);
        arr[0] = 0;
        arr[target] = 0;
        PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2)->{
            return o1[1]-o2[1];
        });
        pq.offer(new int[]{target,0});
        while (!pq.isEmpty()){
            int[] a = pq.poll();
            for(int[] b:lists[a[0]]){
                if(a[1]+b[1]<arr[b[0]]){
                    arr[b[0]] = a[1]+b[1];
                    pq.offer(new int[]{b[0],arr[b[0]]});
                }
            }
        }
        return arr;
    }
}

好的,下面为你详细讲解这段包含Dijkstra算法和A*算法实现的Java代码:

  1. 整体功能概述: 这段代码的主要目的是在一个加权有向图中,先使用Dijkstra算法计算出从一个特定目标节点到其他所有节点的最短距离,然后使用A*算法来找到从起始节点到目标节点的第 k 短的路径。

  2. 代码结构分析

    • 包声明和导入

      package daily_Test.test0422;
      import java.util.*;

      声明了代码所在的包 daily_Test.test0422,并导入了 java.util 包,用于使用 ScannerListPriorityQueue 等工具类。

    • 全局变量声明

      static List<int[]>[] lists;
      static List<int[]>[] lists2;

      声明了两个静态数组 listslists2,用于存储图的邻接表。lists 存储的是反向边(即边的方向与实际相反),lists2 存储的是正向边。

    • 主函数 main

      public static void main(String[] args) {
          Scanner sc = new Scanner(System.in);
          int n = sc.nextInt();
          int m = sc.nextInt();
          lists = new List[n + 1];
          lists2 = new List[n + 1];
      ​
          for (int i = 0; i <= n; i++) {
              lists[i] = new ArrayList<>();
              lists2[i] = new ArrayList<>();
          }
          for (int i = 0; i < m; i++) {
              int o1 = sc.nextInt();
              int o2 = sc.nextInt();
              int len = sc.nextInt();
              lists[o2].add(new int[]{o1, len});
              lists2[o1].add(new int[]{o2,len});
          }
      ​
          int a = sc.nextInt();
          int e = sc.nextInt();
          int k = sc.nextInt();
          int[] res = Dijkstra(e,lists);
          int ans = A_Star(lists2,a,e,k,res);
          System.out.println(ans);
      }
      • 首先,通过 Scanner 读取输入的图的节点数 n 和边数 m

      • 初始化 listslists2 数组,并为每个索引位置创建一个 ArrayList 来存储邻接边。

      • 读取每条边的信息(起始节点 o1、终止节点 o2 和边的长度 len),并将其分别存储到 listslists2 中(lists 存储反向边,lists2 存储正向边)。

      • 读取起始节点 a、目标节点 e 和要找的第 k 短路径的 k 值。

      • 调用 Dijkstra 算法计算从目标节点 e 到其他所有节点的最短距离,结果存储在 res 数组中。

      • 调用 A_Star 算法,传入正向边的邻接表 lists2、起始节点 a、目标节点 ek 值以及 res 数组,获取第 k 短路径的结果 ans 并输出。

    • Dijkstra算法实现函数 Dijkstra

      private static int[] Dijkstra(int target, List<int[]>[] lists) {
          int[] arr = new int[lists.length+1];
          Arrays.fill(arr,Integer.MAX_VALUE);
          arr[0] = 0;
          arr[target] = 0;
          PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2)->{
              return o1[1]-o2[1];
          });
          pq.offer(new int[]{target,0});
          while (!pq.isEmpty()){
              int[] a = pq.poll();
              for(int[] b:lists[a[0]]){
                  if(a[1]+b[1]<arr[b[0]]){
                      arr[b[0]] = a[1]+b[1];
                      pq.offer(new int[]{b[0],arr[b[0]]});
                  }
              }
          }
          return arr;
      }
      • 初始化一个数组 arr 来存储从目标节点到其他所有节点的最短距离,初始值为 Integer.MAX_VALUE,并将目标节点到自身的距离设为 0

      • 创建一个优先队列 pq,按照距离从小到大排序。将目标节点及其距离 0 加入优先队列。

      • 当优先队列不为空时,取出队首元素 a(包含节点编号和到目标节点的距离)。

      • 遍历该节点的所有邻接节点 b,如果通过当前节点 a 到达邻接节点 b 的距离更短,则更新 arr[b[0]] 的值,并将邻接节点 b 及其新的距离加入优先队列。

      • 最终返回存储最短距离的数组 arr

    • A*算法实现函数 A_Star

      private static int A_Star(List<int[]>[] lists2, int start, int end, int k, int[] expect) {
          PriorityQueue<int[]> pq = new PriorityQueue<>((o1,o2)->{
              return o1[0] - o2[0];
          });
          int count = 0;
          pq.offer(new int[]{expect[start],start,0});
          while (!pq.isEmpty()){
              int[] a = pq.poll();
              int e = a[0],node = a[1],l = a[2];
              if(node == end){
                  count++;
                  if(count == k){
                      return node;
                  }
              }
              for(int[] next:lists2[node]){
                  pq.offer(new int[]{e+expect[next[0]]+next[1],next[0],l+next[1]});
              }
          }
          return -1;
      }
      • 创建一个优先队列 pq,按照评估函数值从小到大排序。评估函数值为当前节点到起始节点的距离加上估计的到目标节点的距离(使用 expect 数组中的值)。

      • 初始化计数器 count0,将起始节点及其评估函数值和到起始节点的距离 0 加入优先队列。

      • 当优先队列不为空时,取出队首元素 a(包含评估函数值、节点编号和到起始节点的距离)。

      • 如果当前节点是目标节点,则 count1,当 count 等于 k 时,返回目标节点编号。

      • 遍历当前节点的所有邻接节点 next,计算邻接节点的评估函数值,并将其加入优先队列。

      • 如果遍历完所有节点仍未找到第 k 短路径,则返回 -1

希望以上讲解能帮助你理解这段代码中Dijkstra算法和A*算法的实现逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值