藍橋杯圖論 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;
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章