演算法題解----最短路 : 單源最短路 樸素Dijsktra演算法
今天來介紹一下十分經典的一個最短路演算法:樸素Dijsktra演算法
題目要求:
給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為正值。
請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出−1。
輸入格式
第一行包含整數n和m。
接下來m行每行包含三個整數x,y,z,表示存在一條從點x到點y的有向邊,邊長為z。
輸出格式
輸出一個整數,表示1號點到n號點的最短距離。
如果路徑不存在,則輸出−1。
輸入樣例:
3 3
1 2 2
2 3 1
1 3 4
輸出樣例:
3
那麼這個演算法的思路是怎麼樣的呢?
我們要找到一條從1號點到n號點的最短路 , 不妨把我們已經走過的點當成一個集合,去更新我們沒有走過的點
如下圖所示:
總結一下:樸素迪傑斯特拉演算法 O(n^2)
① dist[1] = 0 其他點賦值為 正無窮
② for (i : 0 - n)
t <- 不在s中的 距離最近的點
s <- t
用t更新其他點的距離
這題適用於稠密圖 所以用鄰接矩陣來儲存圖
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int N= 510;
bool st[N]; //判斷狀態
int dist[N];
int g[N][N]; //鄰接矩陣,儲存圖
int n,m;
int dijsktra()
{
memset (dist , 0x3f,sizeof dist); //初始化 dist陣列
dist[1] = 0; //1號點肯定在集合裡面
for(int i=0;i<n;i++)
{
int t = -1;
for(int j = 1;j <= n ; j++)
if( !st[j] && (t==-1 || dist[t] > dist[j] ) ) //找到目前距離集合最近的點 並且新增進去
t = j;
st[t] = true;
for(int j = 1; j<=n; j ++)
dist[j] = min (dist [j] ,dist[j] + g[t][j]); //新增完點之後就可以更新其他點
}
if(dist[n] == 0x3f3f3f3f) return -1; //如果n號點沒有被更新的話說明走不到n,就沒有最短路
return dist[n];
}
int main()
{
cin.tie(0);
cin>>n>>m;
memset(g,0x3f,sizeof g);
for(int i=1;i<=m;i++)
{
int a,b,w;
cin>>a>>b>>w;
g[a][b] = min(g[a][b],w); //因為這題可能有重邊所以要取最小值
}
int t = dijsktra();
cout <<t <<endl;
return 0;
}