在網絡中,求兩個不同頂點之間的所有路徑中,邊的權值之和最小的那一條路徑
- 這條路徑是兩點之間的最短路徑
*第一個頂點為源點
*最后一個頂點為終點
問題分類
- 單源 最短路徑問題
從固定源點出發,求其到所有其他頂點的最短路徑- (有向)無權圖
- (有向)有權圖
- 多源 最短路徑問題
求任意兩頂點見得最短路徑
有向無權圖的單源最短路徑
按照 遞增 的順序找出給定節點到各個節點的最短路徑
Paste_Image.png
dist[S] = 0
path[]
public UnWeight(Vertex S){
Enqueue(S,Q);
while(!IsEmpty(Q)){
V = Dequeue(Q);
for( V 的鄰接節點 W ){
if(dist[W]!=-1){
dist[W] = dist[V]+1;
path[W] = V;
Enqueue(W,Q);
}
}
}
}
有權有向圖的單源最短路徑
#dijkstra算法
令 S={源點A+已經確定了最短路徑的頂點Vi}
對任一未收錄的·頂點v·,定義dist[v] = A 到 v 的最短路徑長度。
(但該路徑僅僅經過集合S中的頂點)。
若路徑是按照 @遞增 的順序生成的=>
{
真正的最短路必須只經過集合S中的頂點。(反證法)
每次從未收錄的頂點中選一個dist最小的收錄(貪心)。
增加v進入S以后,可能影響另外一個未收錄節點w的dist值
#(比如之前不可達,或是之前的到達路徑比較長==)
# dist[w]=min(dist[v] + E<v,w>, dist[w])
# E<v,w>表示該邊的權重
}
Paste_Image.png
#個人BB
一個富有侵略性的算法。
想象頂點就是一個城池。
占據了頂點以后,依據已經占據的城池向外擴展。
首先擴展就是離出發點最近的領土
(始終是計算出發點和其他點的距離)。
后進來的領土會不會影響舊的領土的距離呢?
@不會
為什么?
加進來的點是按距離順序添加的。
#代碼
void Dijkstra(Vertex s){
while(1){
V = 未收錄頂點中dist最小者;
if(沒有V){
return;
}
collected[V]=true;
for(V 的每個鄰接點 W)
if(collected[W] == false)
if(dist[V] +E(v,w) < dist[W]){
dist[W] = dist[V] + E(v,w);
path[W] = V;
}
}
}
/*不能解決有負邊的情況*/
如果遇到負值圈,就可能會陷入一直死循環的情況。
負值圈
- 方法1:直接掃描所有未收錄頂點 - O(|V|) 適用于稠密圖
- T =O(|V|*|V| + E)
每個節點都要掃一遍。V個點*V
但是其實真是情況是不是,但后面掃的范圍會變小呢...因為大部分被加入到了集合collected 中了。
E 是因為要對每個新加入的點的鄰接點進行處理,所以每條邊都會處理一遍
- 方法2:將dist存在最小堆中-O(log(V)) 適用于稀疏圖
- 更新dist[w]的值 - O(log|V|)
- T = O(|N|log|V| + |E|log|V|) = O(|E|log|V|)
多源最短路徑問題
#floy算法:
#個人BB
其實和dijkstra有點像。就是不斷地添加點到一個集合中。
添加進來的點,
#已經收錄的集合到這個點的路徑
以及 #這個點到達其他點的路徑
暴露了出來。
此時,到達k的路徑,以及從k 到達別人的路徑保持不變。
改變的是其他要經過k來走最短路徑的路。
假設之后,某個點w到k的距離發生了變化,必然是因為加了新的點k1,
那么k1,自然會將 w到k的距離發生變化,而且,會把w經過 k1到達的所有點的距離都會進行改變。
(因為之前,我在擔心,k對整個距離產生變化以后,其他點的結果相當于依賴于看k的距離,但是,如果k的距離改變了,那么豈不是其他結果不準了?
其實k距離發生變化,只有可能是有k1加入導致,如果k1導致k發生變化,那么經過k的路徑,自然一定要經過k1,
因此k1自然會將所有的后面所能到達的點全部化為更新后的最短路徑。
需要多想想。)
public void floyd(){
for(i =0;i<N ;i++){
D[i][j] = G[i][j];
path[i][j] = -1;
}
for(int k=0;k<N;k++){
for(int i =0;i<N;i++){
for(int j=0;j<N;j++){
if(d[i][k]+d[k][j] < d[i][j]){
d[i][j] = d[i][k]+d[k][j];
path[i][j] = k;
}
}
}
}
}
T=O(|V||V||V|)