1. 程式人生 > 其它 >演算法題解----最短路 : 單源最短路 樸素Dijsktra演算法

演算法題解----最短路 : 單源最短路 樸素Dijsktra演算法

今天來介紹一下十分經典的一個最短路演算法:樸素Dijsktra演算法

題目要求: 

給定一個n個點m條邊的有向圖,圖中可能存在重邊和自環,所有邊權均為正值。

請你求出1號點到n號點的最短距離,如果無法從1號點走到n號點,則輸出−1。

輸入格式

第一行包含整數nm。

接下來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;

}