Dijkstra算法介紹+正確性證明+性能分析

算法介紹

  • 源點s,數組d[u]表示s到u的最短距離,空集S,點集Q
  • 初始化:將源點s從點集中去掉,加入S,d[s]=0,?v∈Q,d[v]=w[s][v]\forall v\in Q ,d[v]=w[s][v]?vQ,d[v]=w[s][v]
  • 將Q中d[v]最小的點去掉加入S,并對u∈Q,w[v][u]<∞u\in Q,w[v][u]<\inftyuQ,w[v][u]<進行松弛操作:如果d[v]+w[v,u]<d[u],d[u]=d[v]+w[v,u]d[v]+w[v,u]<d[u],d[u]=d[v]+w[v,u]d[v]+w[v,u]<d[u],d[u]=d[v]+w[v,u]
  • 重復上述步驟直到Q為空集

正確性證明

Dijkstra算法條件:沒有負邊

設源點為s,d[v]表示源點到點v的舉例,d[u,v]表示點u到點v的舉例,w[u,v]表示從點u到點v的一條有向邊的長度,δ(s,v)\delta(s,v)δ(s,v)表示源點到點v的最短路徑長度。

最優子結構性質:任意兩點之間的最短路徑的子路徑仍然是最短路徑

證明:假設s到v的最短路徑上有子路徑u到w,那么δ(s,v)=d[s,u]+d[u,w]+d[w,v]\delta(s,v)=d[s,u]+d[u,w]+d[w,v]δ(s,v)=d[s,u]+d[u,w]+d[w,v]d[u,w]>δ(u,w)d[u,w]>\delta(u,w)d[u,w]>δ(u,w)

那么將d[u,w]d[u,w]d[u,w]替換為δ(u,w)\delta(u,w)δ(u,w)可以得到更好的路徑,那么原路徑就不知最短路徑,這和δ(s,v)\delta(s,v)δ(s,v)的定義矛盾。因此該問題具有最優子結構性質。

引理1:初始化以后進行松弛操作前后?v∈V,d[v]?δ(s,v)\forall v \in V, d[v]\geqslant \delta(s,v)?vV,d[v]?δ(s,v)

證明:由初始化條件,剛初始化以后?v∈V,d[v]?δ(s,v)\forall v \in V, d[v]\geqslant \delta(s,v)?vV,d[v]?δ(s,v)

假設當對點v進行松弛操作時第一次導致上式不再成立,即d[v]=d[u]+w[u,v]<δ(s,v)d[v]=d[u]+w[u,v]<\delta(s,v)d[v]=d[u]+w[u,v]<δ(s,v)

因為點u在點v之前,所以點u滿足上述不等式,d[u]?δ(s,u)d[u]\geqslant \delta(s,u)d[u]?δ(s,u)

由定義容易得到w[u,v]?δ(u,v)w[u,v]\geqslant \delta(u,v)w[u,v]?δ(u,v),因此d[v]=d[u]+w[u,v]?δ(s,u)+δ(u,v)d[v]=d[u]+w[u,v]\geqslant \delta(s,u)+\delta(u,v)d[v]=d[u]+w[u,v]?δ(s,u)+δ(u,v)

由三角不等式d[v?δ(s,u)+δ(u,v)?δ(s,v)d[v\geqslant \delta(s,u)+\delta(u,v)\geqslant \delta(s,v)d[v?δ(s,u)+δ(u,v)?δ(s,v),與上面假設矛盾

因此初始化以后進行松弛操作前后?v∈V,d[v]?δ(s,v)\forall v \in V, d[v]\geqslant \delta(s,v)?vV,d[v]?δ(s,v),引理1成立

引理2:假設存在s到v的最短路徑:s->…->u->v,d[u]=δ(s,u)d[u]=\delta(s,u)d[u]=δ(s,u),那么在點u對v進行松弛操作d[v]=d[u]+w[u,v]d[v]=d[u]+w[u,v]d[v]=d[u]+w[u,v]之后,d[v]=δ(s,v)d[v]=\delta(s,v)d[v]=δ(s,v)

證明:由最優子結構性質,s到v的路徑中s到u為點u的最短路徑,δ(s,v)=δ(s,u)+w[u,v]\delta(s,v)=\delta(s,u)+w[u,v]δ(s,v)=δ(s,u)+w[u,v]

d[u]+w[u,v]=δ(s,u)+w[u,v]=δ(s,v)d[u]+w[u,v]=\delta(s,u)+w[u,v]=\delta(s,v)d[u]+w[u,v]=δ(s,u)+w[u,v]=δ(s,v),由引理1,在松弛操作以前d[v]?δ(s,v)d[v]\geqslant \delta(s,v)d[v]?δ(s,v),因此松弛操作會保證d[v]=δ(s,v)d[v]=\delta(s,v)d[v]=δ(s,v),等證。

當算法結束后,d[v]=δ(s,v)d[v]=\delta(s,v)d[v]=δ(s,v)

證明:因為算法中將點加入確定的集合后就不再進行修改,所以相當于證明加入確定集合時d[v]=δ(s,v)d[v]=\delta(s,v)d[v]=δ(s,v)

由引理1,假設加入確定集合時第一個出現d[v]>δ(s,v)d[v]>\delta(s,v)d[v]>δ(s,v)為節點v(開始使用反證法)

假設s到v的最短路徑為s->…->x->y->…->v,x是該路徑在確定集合中的最后一個元素,y是該路徑不在確定集合中的第一個元素。

因為v是第一個出現的點,而x在v之前加入,所以d[x]=δ(s,x)d[x]=\delta(s,x)d[x]=δ(s,x)

由最優子結構,s->…->x->y是s到y的一條最短路徑,此時x已經進行了松弛操作

由引理2,d[y]=δ(s,y)d[y]=\delta(s,y)d[y]=δ(s,y)

因為y是s到v路徑上的一點,所以δ(s,v)?δ(s,y)\delta(s,v)\geqslant \delta(s,y)δ(s,v)?δ(s,y)

加入確定集合時d[v]d[v]d[v]是所有未加入點中最小的,所以d[v]?d[y]=δ(s,y)?δ(s,v)d[v]\leqslant d[y]=\delta(s,y)\leqslant\delta(s,v)d[v]?d[y]=δ(s,y)?δ(s,v),與假設矛盾。證畢。

復雜度分析

初始化的復雜度為Θ(∣V∣)\Theta(|V|)Θ(V)

總共要循環|V|次尋找點集中d[]最小的元素,復雜度為O(∣V∣T尋找最小元素)O(|V|T_{尋找最小元素})O(VT?)

對于每個點都需要對所指向的點進行降低鍵值操作,由握手定理,總共需要降低出度的總和即|E|,復雜度為O(∣E∣T降低鍵值)O(|E|T_{降低鍵值})O(ET?)

因此總共的復雜度為O(∣V∣T尋找最小元素+∣E∣T降低鍵值)O(|V|T_{尋找最小元素}+|E|T_{降低鍵值})O(VT?+ET?),通過使用不同的數據結構我們可以得到不同的復雜度。特殊的,如果我們使用數組,復雜度為O(∣V∣2)O(|V|^2)O(V2),如果我們使用二叉堆,復雜度為O((V+E)logV)O((V+E)logV)O((V+E)logV),如果我們使用斐波那契堆,可以得到最優秀的復雜度O(E+VlogV)O(E+VlogV)O(E+VlogV)

和BFS的關系

特殊地,如果邊的權值全部為1(或者相等),那么BFS就是Dijkstra算法,復雜度為O(V+E)O(V+E)O(V+E)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383647.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383647.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383647.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux C 實現一個簡單的線程池

https://www.cnblogs.com/GyForever1004/p/9185240.html 線程池的定義 線程池是一種多線程處理形式&#xff0c;處理過程中將任務添加到隊列&#xff0c;然后在創建線程后自動啟動這些任務。線程池線程都是后臺線程。每個線程都使用默認的堆棧大小&#xff0c;以默認的優先級…

斐波那契數列求解+尾遞歸

1.普通遞歸 這里觀察f[4]的遞歸樹代替f[10]的遞歸樹&#xff08;后者比較大&#xff0c;畫不下&#xff09;。 使用遞歸求解的時候復雜度為T(n)T(n?1)T(n?2)T(n)T(n-1)T(n-2)T(n)T(n?1)T(n?2)&#xff0c;觀察遞歸樹&#xff0c;發現降速最快的是最右邊每次減2&#xff0c…

循環服務器,并發服務器模型以及I/O多路轉接模型

https://blog.csdn.net/xinianbuxiu/article/details/53455784 一、基于TCP/IP協議的基本循環服務器 tcp_server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #incl…

c++繼承父類的子類,如何調用父類的同名函數?

https://blog.csdn.net/qq_26399665/article/details/52080215 子類調用父類的同名函數&#xff1a; 子類和父類返回值參數相同&#xff0c;函數名相同&#xff0c;有virtual關鍵字&#xff0c;則由對象的類型決定調用哪個函數。 子類和父類只要函數名相同&#xff0c;沒有vi…

LCS最長公共子串

問題介紹 LCS問題(longest common subsequence problem)指的是求解兩個字符串最長公共子序列問題。這里的子序列是可以不連續的。LCS問題廣泛地出現在計算生物學中&#xff08;DNA序列、系統生成樹等等&#xff09;。這里介紹如何解決LCS問題&#xff0c;以及算法的正確性證明…

將字符串中的空格用%20替換

如果不需要原地操作&#xff0c;則一遍遍歷&#xff0c;將非空串復制&#xff0c;遇到空格加上%20&#xff0c;如果需要原地操作&#xff0c;首先進行遍歷出空格的個數x,然后擴容2x,從后往前遍歷實現。如果非空格字符串比空格字符串多的多的時候而且字符串非常長的時候使用原地…

12步輕松搞定python裝飾器

http://python.jobbole.com/81683/ 呵呵&#xff01;作為一名教python的老師&#xff0c;我發現學生們基本上一開始很難搞定python的裝飾器&#xff0c;也許因為裝飾器確實很難懂。搞定裝飾器需要你了解一些函數式編程的概念&#xff0c;當然還有理解在python中定義和調用函數…

操作系統【六】虛擬內存

傳統存儲管理方式的不足 一次性&#xff1a;作業必須一次性全部裝入內存后才能開始運行。這會造成&#xff1a;當作也很大時不能全部裝入內存&#xff1b;當大量作業要求運行時&#xff0c;由于內存無法容納所有作業&#xff0c;因此只有少量作業能夠運行&#xff0c;導致多道…

python裝飾器詳解

https://blog.csdn.net/xiangxianghehe/article/details/77170585 你會Python嘛&#xff1f; 我會&#xff01; 那你給我講下Python裝飾器吧&#xff01; Python裝飾器啊&#xff1f;我沒用過哎 以上是我一個哥們面試時候發生的真實對白。 ———————————————-分…

SQL Server【一】簡介和基本概念和命令

數據結構和數據庫的區別 數據庫是應用軟件級別研究數據的存儲和操作&#xff08;主要針對磁盤上的數據&#xff09; 數據結構是在系統軟件級別研究數據的存儲和操作&#xff08;主要是針對內存中的數據&#xff09; 對硬盤數操作是數據庫的強項&#xff0c;是數據庫研究的核心…

SQL Server【二】單表查詢

查詢 計算列 select * from emp; -- *通配符&#xff0c;表示所有的字段 -- from emp 從emp表查詢select empno, ename from emp; select ename as "員工姓名", sal*12 as "年薪" from emp;-- as可以省略&#xff0c;用于設置字段名 -- 注意用雙引號將字…

SQL Server【三】連接查詢

將兩個表或者兩個以上的表以一定的連接條件連接起來&#xff0c;從中檢索出滿足條件的數據。 內連接 使用inner join&#xff0c;inner可以省略 -- 查詢員工的姓名和部門名稱 select "E".ename as "員工姓名", "D".dname as "部門名稱&q…

Linux下網絡socket編程——實現服務器(select)與多個客戶端通信

一、關于socket通信 服務器端工作流程&#xff1a; 調用 socket() 函數創建套接字 用 bind() 函數將創建的套接字與服務端IP地址綁定調用listen()函數監聽socket() 函數創建的套接字&#xff0c;等待客戶端連接 當客戶端請求到來之后調用 accept()函數接受連接請求&#xff0c…

SQL Server【四】

identity 主鍵自動增長&#xff0c;用戶不需要為identity修飾的主鍵賦值 create table student (std_id int primary key identity(10,5),--(10,5)可以省略&#xff0c;默認為(1,1)std_name nvarchar(200) not null ) select * from student insert into student values (張三…

TCP服務器/客戶端實例(C/C )

1.1、Linux下的TCP服務器&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h>void error_handling(char *mess…

pip代理解決pip下載失敗問題

在用pip下載各種庫的時候發現速度實在是太慢了&#xff0c;還會有各種奇奇怪怪的問題&#xff0c;動不動就玄學失敗。 在網上找來找去找到知乎上一位大佬的回答&#xff1a;傳送門&#xff0c;用了豆瓣的代理。哇咔咔&#xff0c;媽媽再也不用擔心我下載失敗了。 代理&#x…

實現Linux select IO復用C/S服務器代碼

服務器端#include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #include<sys/socket.h> #include<sys/stat.h> #include<arpa/inet.h> #include <sys/select.h>#define MAXBUF 256 #define MAXLISTEN…

Bellman-Ford算法和SPFA算法

Belloman-Ford算法 算法介紹 Dijkstra可以解決單源無負邊最短路徑問題。但是當遇到含有負邊的單源最短路徑問題就需要使用Bellman-Ford算法來解決。Bellman-Ford算法還可以檢測出負環。 算法步驟 源點s,數組d[u]d[u]d[u]表示s到u的最短距離初始化&#xff1a;d[s]0d[s]0d[s…

C語言實現單鏈表操作

SLIST_H #ifndef __SLIST_H__ #define __SLIST_H__ #include<cstdio> #include<malloc.h> #include<assert.h> typedef int ElemType; typedef struct Node { //定義單鏈表中的結點信息 ElemType data; //結點的數據域 struct Node *next; //結點的指針…

計算機網絡【4】傳輸層

概述 傳輸層是只有主機才有的層次 傳輸層的功能&#xff1a; 傳輸層提供進程和進程之間的邏輯通信&#xff08;網絡層提供主機與主機之間的邏輯通信&#xff09;復用和分用傳輸層對收到的報文進行差錯檢測 傳輸層有兩個協議&#xff1a; 面向連接的傳輸層控制協議TCP&…