蓝桥杯图论 Dijkstra 单源最短路讲解

什么是单源最短路?

说实话,兄弟刚接触这个东西的时候是懵逼的,单源最短路?哇,难不成是以前看的科幻电影中的高科技武器的科技?
学习过程中也很懵逼,给很多文字误导了其实就一句话:“从一个源头出发,到任意一个节点的最短距离”

Dijkstra算法是怎么被想出来的?

看见书上稀稀疏疏的写了一大堆,反正就是没看懂。逻辑归纳出来就是,为了证明而证明,并不符合人类的正常认识。
正常人的认识肯定是,从当前点出发,优先走最短的路径,则到达的点的路径,肯定是最短的。
简单的举一个例子:如果你从一栋楼出发,有任意条道路,可以到另外的一些楼。那么,你肯定会用脑子想。

我现在走最短的路径,走到下一栋楼,那么我到下一栋楼所走的路肯定是最近的。
BUT,如果下一栋楼的距离加下一栋楼到另外一栋楼的距离出发(或以前任意楼出发的距离)
超过了从第一栋楼出发的距离,那么这条路不是最短。

理论证明

路径:从源头出发加上,一条由所经过边消耗组成的节点集合。
最短节点路径:由初始边到达目标节点最短的节点集合。

1、可知,由源头节点A出发,有任意一节点C,可以用A->B->C或A->C访问。
	这个时候我们比较那条路更短,实际上比较的是(A-B)->C与A->C路径大小
	归纳的看来,可以认为,我们实质上是在比较要到达任意一个节点C的最短路径,那么就是他前面所走路径加上从该路径出发到C的距离。

2、从A出发,到达B的距离既为最小,因为到达B的消耗是A最小的边。
不可能存在一边D可使得A->D->B为最短。
则若 A->B->C 小于A->C 则不可能存在第四点小于A->B->C 
因此,可以理解为从=目前已探索到的最短路径到达的节点出发,如果可以联通到点C。并且小于A->C距离,则A-B-C
为最短路径(贪心算法,总体路径最短)

思路实现(堆优化)

现在有N路径,都可以到达C,那我们是不是把这两条路径按照升序排列。
第0位上的为最小,它的路径长度就是最短路径大小。
如:(C1=1,C2=3,C3=4)
C1 C2 C3的路径是由什么转变过来的呢?答:上一步的路径+达到C的花费
看到这里大概会想到,优先队列来存放到达C的路径,不就是我们理论证明的思路吗?
优先队列只要访问到C,那么C的路径就是最小

import java.util.*;
/**
	有向图,dijkstra
**/
public class 单源最短路径重置 {
	
	static int V;
	static int E;
	static int target;
	static int count = 0;
	static Edge[] edges;
	static int[] head;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		V = sc.nextInt();
		E = sc.nextInt();
		target = sc.nextInt();
		edges = new Edge[E];
		head = new int[V + 1];
		for (int i = 0; i <= V; i += 1)
			head[i] = -1;
		for (int i = 0; i < E; i++) {
			addEdge(sc.nextInt(), sc.nextInt(), sc.nextInt());
		}
		dijkstra();
	}

	public static void dijkstra() {
		boolean[] vis = new boolean[V+1];
		int[] disTo = new int[V + 1];
		PriorityQueue<node> pq = new PriorityQueue<node>();
		pq.add(new node(target, 0));
		for(int i=0;i<disTo.length;i++)disTo[i]=Integer.MAX_VALUE;
		disTo[target]=0;
		while (!pq.isEmpty()) {
			node tmp = pq.poll();
			
			if (vis[tmp.to])
				continue;
			vis[tmp.to] = true;
			disTo[tmp.to] = tmp.weight;
			for (int i = head[tmp.to]; i != -1; i = edges[i].next) {
				Edge nextEdge=edges[i];
				if(tmp.weight+nextEdge.weight<disTo[nextEdge.to]) {
					disTo[nextEdge.to]=tmp.weight+nextEdge.weight;
					pq.offer(new node(nextEdge.to,disTo[nextEdge.to]));
				}
			}
		}
		for(int i =1;i<disTo.length;i++)System.out.print(disTo[i]+" ");
	}

	public static class node implements Comparable<node>{
		int to, weight;

		public node(int to, int weight) {
			this.to = to;
			this.weight = weight;
		}
		@Override
		public int compareTo(node o) {
		return this.weight-o.weight;
		}
	}

	public static void addEdge(int from, int to, int weight) {
		edges[count] = new Edge(to, weight, head[from]);
		head[from] = count++;
	}

	public static class Edge {
		int to, weight, next;

		public Edge(int to, int weight, int next) {
			this.to = to;
			this.weight = weight;
			this.next = next;
		}
	}
}
原创文章 12 获赞 25 访问量 396

猜你喜欢

转载自blog.csdn.net/qq_42499133/article/details/105672597