Dijkstra、BFS求有权图、无权图最短路径[Java]

一、Dijkstra算法解决有权图的最短路径问题

1. pre

	迪杰斯特拉算法采用贪心的策略,集合T{}用来存放当前已找到的最短路径节点集合。将起始点的路径权重赋
为0,当前节点不能到达的节点权重赋为无穷大。

2. 算法演示

下面展示的是无向带权值图求最短路径:
2.1

具体步骤:
每次添加路径最小值的节点到T集合。
2.2
结合图理解:
2.3
邻接表结构:链表头结点存放的是下标。
2.4

3. Java代码

题目:一共有n个点,m条无向边,每条边都有长度d和花费p,给定起点s终点t,要求输出起点到终点的最短距离
及其花费,如果最短距离有多条路线,则输出花费最少的。
输出:最小距离和花费。

创建Vertex类,构建邻接表:

class Edge {
	// 存放边的信息,next表示下一个节点,dist表示长度,cost表示花费
    int next;
    int dist;
    int cost;
    public Edge(int next, int dist, int cost) {
        this.next = next;
        this.dist = dist;
        this.cost = cost;
    }
}

class Vertex {
    int num;
    ArrayList<Edge> edge;  // 使用链表结构存储
    public Vertex(int num) {
        this.num = num;
        this.edge = new ArrayList<Edge>();
    }
}

ACM模式:

Scanner in = new Scanner(System.in);
while (in.hasNext()) {
	int n = in.nextInt(); // 点数
    int m = in.nextInt(); // 边数
    if (m == 0) break;
    Vertex[] list = new Vertex[n + 1];
    // 初始化Vertex
    for (int i = 1; i <= n; i++){
    	list[i] = new Vertex(i);
    }
    for (int i = 0; i < m; i++) {
        int a = in.nextInt();
        int b = in.nextInt();
        int dist = in.nextInt();  // 长度
        int cost = in.nextInt();  // 花费
        list[a].edge.add(new Edge(b, dist, cost));  // a->b 的长度和花费
        list[b].edge.add(new Edge(a, dist, cost));  
    }
    int s = in.nextInt(); // 起点
    int t = in.nextInt(); // 终点
    boolean[] marked = new boolean[n + 1];  // 用来记录当前节点是否更新
    int[] cost = new int[n + 1];
    int[] dist = new int[n + 1];
    for (int i = 1; i <= n; i++) {
        cost[i] = Integer.MAX_VALUE;  // 初始花费设为max
        dist[i] = -1;  // 不可达用-1表示
        marked[i] = false;
    }
    dist[s] = 0;
    cost[s] = 0;
    marked[s] = true;
    int p = s;  // 当前起点p
    // Dijkstra
    for(int i=1;i<=n;i++){
      for(int j=0;j<list[p].edge.size();j++){
          int next = list[p].edge.get(j).next;
          int c = list[p].edge.get(j).cost;
          int d = list[p].edge.get(j).dist;
          if(marked[next]==true) continue;
          // 三种情况进行更新:距离未更新时、距离需更新时、距离相等花费变小时
          if(dist[next]==-1 || dist[next]>dist[p]+d || dist[next]== dist[p]+d && cost[next]>cost[p]+c){
              dist[next] = dist[p] + d;
              cost[next] = cost[p] + c;
          }
      }
      int min = Integer.MAX_VALUE;
      for(int j=1;j<=n;j++){
          if(marked[j]==true) continue;
          if(dist[j]==-1) continue;
          if(dist[j]<min){
              min = dist[j];
              p = j;
          }
      }
      marked[p] = true;
  }
  System.out.printf("%d %d\n", dist[t],cost[t]);

二、BFS算法解决无权图的最短路径问题

1. pre

广度优先搜索算法(BFS),是一种利用队列实现的搜索算法。

深度优先搜索算法(DFS),是一种利用递归实现的搜索算法。

2. 算法

题目:给定n个节点,节点从0依次编号,0固定为根节点,若节点设置障碍则不可达,输出从根节点到叶子结点的
路径(只有一条边相连的为叶子结点),否则输出NULL。
输入:
	第一行 n 【节点数】
	第二行 m 【边数】
	接下来m行 x y 【x与y相连】
	第m+3行 b 【接下来有b个障碍物节点】
	接下来b行 k 【节点k有障碍物】 
例:
	7
	6
	0 1
	0 3
	1 2
	3 4
	1 5
	5 6
	1
	4

因为使用邻接表结构存储相邻节点,不要求是二叉树,为了方便画成树的形状。

2.1
同样的创建Vertex类,构建邻接表:

class Edge {
    int next;
    public Edge(int next) {
        this.next = next;
    }
}
class Vertex {
    int num;
    ArrayList<Edge> edge;
    public Vertex(int num) {
        this.num = num;
        this.edge = new ArrayList<Edge>();
    }
}

bfs

public static int bfs(int x, Vertex[] list, int[] book, int[] child){
   Queue<Integer> queue = new LinkedList<>();
   queue.offer(x);
   while (!queue.isEmpty()){
       int top = queue.poll();
       int size = list[top].edge.size();  // 相连的边的个数
       if (size == 0){
           return top;
       }else{
           for (int i = 0; i < size; i++) {
               int next = list[top].edge.get(i).next;
               if (book[next] == 1) continue;
               queue.offer(next);
               child[next] = top;
           }
       }
   }
   return -1;
}
Scanner scan = new Scanner(System.in);
while (scan.hasNext()) {
    int n = scan.nextInt();
    int m = scan.nextInt();
    int[] child = new int[n];  
    Arrays.fill(child, -1);
    Vertex[] list = new Vertex[n];
    for (int i = 0; i < n; i++)
        list[i] = new Vertex(i);
    for (int i = 0; i < m; i++) {
        int a = scan.nextInt();
        int b = scan.nextInt();
        list[a].edge.add(new Edge(b));  // 单向
    }
    int block_num = scan.nextInt();
    int[] book = new int[n];
    for (int i = 0; i < block_num; i++) {
        int z = scan.nextInt();
        book[z] = 1;
    }
    int ans = bfs(0, list, book, child);
    if (ans == -1) {
        System.out.println("NULL");
    } else {
        Deque<Integer> res = new LinkedList<>();
        while (ans != -1) {
            res.addFirst(ans);
            ans = child[ans];
        }
        while (!res.isEmpty()) {
            System.out.print(res.poll() + " ");
        }
    }
}

例:
2

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dijkstra算法是一种用于计算最短路径的贪心算法。它可以应用于有向和无向,但是在本文中我们只考虑有向的情况。下面是Java实现Dijkstra算法有向最短路径的示例代码: ```java import java.util.*; public class DijkstraAlgorithm { private final int MAX_VALUE = Integer.MAX_VALUE; // 定义一个最大值 public int[] dijkstra(int[][] graph, int start) { int n = graph.length; int[] distance = new int[n]; // 存储起点到每个顶点的距离 boolean[] visited = new boolean[n]; // 记录顶点是否已经被访问 Arrays.fill(distance, MAX_VALUE); // 初始化距离为最大值 distance[start] = 0; // 起点到自己的距离为0 for (int i = 0; i < n; i++) { int u = findMinDistance(distance, visited); // 找到当前未访问的距离最小的顶点 visited[u] = true; // 标记该顶点已经被访问 for (int v = 0; v < n; v++) { if (!visited[v] && graph[u][v] != MAX_VALUE && distance[u] != MAX_VALUE && distance[u] + graph[u][v] < distance[v]) { distance[v] = distance[u] + graph[u][v]; // 更新起点到该顶点的距离 } } } return distance; } // 找到当前未访问的距离最小的顶点 private int findMinDistance(int[] distance, boolean[] visited) { int minDistance = MAX_VALUE; int minIndex = -1; for (int i = 0; i < distance.length; i++) { if (!visited[i] && distance[i] < minDistance) { minDistance = distance[i]; minIndex = i; } } return minIndex; } public static void main(String[] args) { int[][] graph = { {0, 2, 4, MAX_VALUE, MAX_VALUE}, {MAX_VALUE, 0, 1, 4, 2}, {MAX_VALUE, MAX_VALUE, 0, MAX_VALUE, MAX_VALUE}, {MAX_VALUE, MAX_VALUE, MAX_VALUE, 0, 3}, {MAX_VALUE, MAX_VALUE, MAX_VALUE, MAX_VALUE, 0} }; int start = 0; DijkstraAlgorithm dijkstraAlgorithm = new DijkstraAlgorithm(); int[] distance = dijkstraAlgorithm.dijkstra(graph, start); System.out.println(Arrays.toString(distance)); } } ``` 在上面的示例代码中,我们使用一个二维数组来表示有向的邻接矩阵,其中MAX_VALUE表示两个顶点之间没有连接。在dijkstra方法中,我们首先初始化起点到每个顶点的距离为最大值,然后遍历每个顶点,找到当前未访问的距离最小的顶点,并将该顶点标记为已访问。然后,我们遍历与该顶点相邻的顶点,并更新起点到这些顶点的距离。最后返回起点到每个顶点的最短距离数组。 在上述示例中,我们使用了一个findMinDistance方法来找到当前未访问的距离最小的顶点,并使用Arrays.fill方法将distance数组初始化为最大值。这里需要注意的是,我们使用了Integer.MAX_VALUE来表示两个顶点之间没有连接,因为在Dijkstra算法中,我们需要比较两个顶点之间的距离,而使用一个较大的值可以避免出现负权边的情况。 在main方法中,我们定义了一个有向的邻接矩阵,然后调用dijkstra方法计算起点到每个顶点的最短距离,并输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值