Dijkstra算法是解決有向帶權圖中最短路徑的算法。
我用自己的語言解釋Dijkstra算法的過程:
1.首先有一個有向帶權圖G=(V,E),V爲頂點集合,E爲邊集合,用鄰接矩陣map[n][n]來儲存。
確定一個起始點origin,有一個輔助集合s,一開始將origin併入s中。
有一個輔助數組dist[n],dist[i]表示i距離origin的最短距離,初始化dist[i]=map[origin][i]。若不存在弧則相應等於無窮大
2.找一個頂點j,使頂點j存在於V-s中(即頂點j屬於V但不屬於s),並且dist[j]是所有V-s頂點中最小的一個,將頂點j併入s中;
3.遍歷以頂點j爲地點的弧<j,k>且k屬於V-s中,如果dist[k] > dist[j] + weight<j,k>,則令dist[k]=dist[j] + weight<j,k>;
這一步相當於搭一個頂點j的順風車。已知origin-j最短的距離是dist[j],若origin-k的(直接)距離大於
dist[j] + weight<j,k>,說明源點到頂點k的路徑可以通過頂點j這條路而減少距離。
4.重複2,3步,直到s中包含了V中所有的頂點,結束算法。
代碼:(C++實現)
#include <iostream>
#define MAX 999999
using namespace std;
const int n =5; //頂點數量
int map[n+1][n+1]; //有向圖 鄰接矩陣
int dist[n+1]={MAX}; //起點到其餘頂點的距離
int s[n+1]={0}; //頂點集合
int pre[n+1]={0}; //每個頂點的直接前驅
void findMin(int origin)
{
int i,j;
for(j=1;j<=n;j++)
{
int minWeight=MAX; //dist[i]中最小權值
int minPoint =0; //最小權值的點
for(i=1;i<=n;i++)
{
if( !s[i] && dist[i]<= minWeight ) //尋找不在s中的最小權值的點
{
minWeight = dist[i];
minPoint = i;
}
}
if(minPoint==0) //如果沒有找到,說明所有頂點都以併入s中
return ;
s[minPoint]=1; //將最小權值的點並中s中
//修改不在s中的其他頂點的dist值
for(i=1;i<=n;i++)
{
if( !s[i] && map[minPoint][i] != MAX)
if(dist[i] > dist[minPoint] + map[minPoint][i])
{
dist[i] = dist[minPoint] + map[minPoint][i];
pre[i] = minPoint; //將需要修改的頂點的直接前驅改爲最小的權值點
}
}
}
}
void findPath(int i)
{
if(pre[i]==0) //表示i可能是起始點,也可能是和起始點不強連通的的點
{
if(dist[i] != MAX) //起始點
cout<<i;
else //與起始點不強連通的點
cout<<"不存在";
return ;
}
findPath(pre[i]);
cout<<"-"<<i;
}
int main()
{
int i,j;
int weight;
int origin; //起點頂點
//鄰接矩陣初始化
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
map[i][j] = MAX;
cout<<"請輸入權值"<<endl;
cout<<"格式:i j weight"<<endl;
cout<<"示例:1 2 2 即有一條弧<1,2>,權值爲2,未輸入數據則默認爲無窮大"<<endl;
cout<<"結束時輸入 0 0 0"<<endl;
cout<<"*************************"<<endl;
while(1)
{
cin>>i>>j>>weight;
if(i==0 && j==0 && weight==0)
break;
else
map[i][j] = weight;
}
cout<<"請輸入起始點"<<endl;
cin>>origin;
//也可以通過遍歷鄰接矩陣找到入度爲0的點找到源點
map[origin][origin]=0;
/*初始化dist[]與pre[]
*dist[]初始值爲源點與其餘頂點i的權值,即map[origin][i],不存在弧則爲無窮大MAX
*pre[] 中,若其餘頂點i與源點有弧,則pre[i]=1,否則等於0
*/
for(i=1;i<=n;i++)
{
dist[i]=map[origin][i];
if(map[origin][i] != MAX && map[origin][i] != 0)
pre[i]=origin;
}
s[origin]=1;//初始化s[],即將源點加入s中
findMin(origin);
/*輸出頂點的頂點的最短路徑*/
for(i=1;i<=n;i++)
{
cout<<"從起點"<<origin<<"去頂點"<<i<<"的最短路徑爲:";
findPath(i);
cout<<" 最短距離爲:"<<dist[i];
cout<<endl;
}
return 0;
}
實現示例:
例子1:
例子2: