經典算法——最短路徑(Floyd+Dijkstra)

Floyd

時間複雜度:O(n^3)
簡介:作爲最短路算法中複雜度最高的算法沒有之一,標誌性結構三層循環,核心結構本質DP思想具 有動態規劃的無後效性

他真的沒有優點啦?!不,他有!

雖然SPFA,Dijkstra比他跑得快,但是隻能算一個點到任意一點的最短路徑,可Floyd是解決多源最短路的最佳方法,他能計算任意兩點之間的最短距離

if(d[i][j]>d[i][k]+d[k][j])
	d[i][j]=d[i][k]+d[k][j]

想必這個代碼我們在這個算法裏並不陌生
設:總共有n個節點
我們在尋找的任意兩點之間最短路時在中轉點k我們爲何能夠確定下這個k點,是因爲我們由三層循環已經判斷了在這個點k前的路徑是最短的,所運用的方法是O(n^2)的鬆弛
DP的無後效性,體現在k不僅是中轉點還是一個狀態變量,在選中k點前k已經作爲i或j進行枚舉了,所以說每次在確定下一個點的時候我們都保證了在1到k之間已經是最優路徑
實現代碼如下:

for(int k=1;k<=n;k++)
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(d[i][j]>d[i][k]+d[k][j])
				d[i][j]=d[i][k]+d[k][j];

Dijkstra

時間複雜度:O(n^3)
簡介:利用的思想是貪心思想,準備階段爲將起點到各個點的距離都統計出來,核心階段鬆弛遍歷過的點,看是否能夠作爲中轉點使其起點到另一個點的距離更短
借用大佬的圖舉個例子
enter image description here
我們要想計算出1號點到各個點的最短路徑
第一步
enter image description here
我們將兩相鄰點的距離進行統計
第二步
將1到各點的距離用一個dis數組進行儲存,不能直接到達的用∞表示
第三步
尋找距離1點最近的點然後將最近的這個點當作中轉點,然後重新計算經過該中轉點後能夠直接到達的點的距離,然後再次尋找此時距離1點最近的點,以此類推最後能確定1點到各個點的最近距離
enter image description here
核心代碼實現

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
struct edge
{
int u,v,x;
} ed[1000010];
struct node
{
	int x,y;
bool operator <(const node & a)const
{
	return y>a.y;
}
};
priority_queue<node>que;
int head[1000010];
int dis[1000010];
int n,m,s,cnt;
void add(int x,int y,int z)
{
cnt++;
ed[cnt].u=head[x];
ed[cnt].v=y;
ed[cnt].x=z;
head[x]=cnt;
}
void dij()
{
for(int i=1; i<=n; i++)
	dis[i]=2147483647;
dis[s]=0;
que.push((node)
{
	s,0
});
while(!que.empty())
{
	node temp=que.top();
	que.pop();
	int x=temp.x,y=temp.y;
	if(y!=dis[x])
		continue;
	for(int i=head[x]; i; i=ed[i].u)
	{
		if(dis[ed[i].v]>dis[x]+ed[i].x)
		{
			dis[ed[i].v]=dis[x]+ed[i].x;
			que.push((node)
			{
				ed[i].v,dis[ed[i].v]
			});
		}
	}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=1; i<=m; i++)
{
	int x,y,z;
	cin>>x>>y>>z;
	add(x,y,z);
}
dij();
for(int i=1; i<=n; i++)
	cout<<dis[i]<<" ";
return 0;
}

本蒟蒻目前只會這兩種算法
至於SPFA和Bellman-Ford還需要努力
敬請期待!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章