Dijkstra算法的原理:
從某個源點到其余各頂點的最短路徑,即單源點最短路徑(僅適合非負權值圖)。單源點最短路徑是指:給定帶權有向圖G和源點v,求從v到G中其余各頂點的最短路徑。迪傑斯特拉(Dijkstra)提出了按路徑長度遞增的順序產生各頂點的最短路徑算法。
該算法的基本思想是:
(1)設置兩個頂點的集合S和T=V-S,集合S中存放已找到最短路徑的頂點,集合T存放當前還未找到最短路徑的頂點;
(2)初始狀態時,集合S中只包含源點v0;
(3)從集合T中選取到某個頂點vi(要求vi到v0的路徑長度最小)加入到S中;
(4)S中每加入一個頂點vi,都要修改頂點v0到T中剩余頂點的最短路徑長度值,它們的值為原來值與新值的較小者,新值是vi的最短路徑長度加上vi到該頂點的路徑長度;
(5)不斷重復(3)和(4),直到S包含全部頂點。
算法設計:
1.首先函數里面運用二維數組cost[n][n]實現圖的臨界矩陣存儲,數組dist[n]表示源點到節點n的最短距離,S[n]表示某一節點n是否已經進入集合S,如果進入則將S[i]置為1,否則為0。pre[n]表示當前節點n的前驅節點(用來輸出路徑)。
2.在開始遍歷之前,首先給數組D[n]賦值為源點到該點的距離,這樣便能第一次找到源點到相鄰節點的最短距離(dist[i]=cost[v][i];)。
3.下面找出最短距離:
if((!S[j])&&(dist[j]<min))
{
min=dist[j];
u=j;
}
4.更新各節點的最短距離:
for(int k=0;k<n;k++)
{
if((!S[k])&&(dist[k]>dist[u]+cost[u][k])) //調整未加入S的點的距離值
{
D[k]=D[u]+cost[u][k];
pre[k]=u; //若通過u減小了k的距離值,則修改k的前趨為u
}
}
4.另外,若從原點無法到達頂點x,則令其前趨為-1:pre[x]=-1,在輸出判別一下就可以了。還要提醒的一點是輸入輸出的頂點的標號與實際存儲的數組下標相差為1,應該要分辨清楚。
代碼實現:
#include<cstdio>
using namespace std;
#define max 10000
#define inf 20000
int n,e; //頂點數n,邊的條數e
int cost[20][20]; //臨界矩陣
int dist[20]; //存儲最短路徑的長度值
int pre[20]; //存儲一個頂點在其最短路徑的前趨
int S[20]; //標志數組,若為已經找到最短路徑的結點則為1,否則為0
void Dijkstra(int v){
for(int i=0;i<n;i++){
dist[i]=cost[v][i]; //初始化
S[i]=0; //標志位初始為0
if(dist[i]<max)
pre[i]=v; //若存在邊,則前趨為原點
else
pre[i]=-1; //否則,前趨為-1,不可達
}
S[0]=1; //原點標志為1
for(int i=0;i<n-1;i++){ //循環n-1次
int u; //u為待選頂點
int min=inf; //令初始最小值>max,使距離值為max的頂點也能加到S中
for(int j=0;j<n;j++){
if((!S[j])&&dist[j]<min){ //尋找距離S最小的頂點u
min=dist[j];
u=j;
}
}
S[u]=1; //將其標志設置為1
for(int k=0;k<n;k++){ //調整未加入S的點的的距離值
if((!S[k])&&dist[k]>dist[u]+cost[u][k]){
dist[k]=dist[u]+cost[u][k];
pre[k]=u; //若通過u減小了k的距離,則修改k的前趨為u
}
}
}
printf("\nThe result:\n"); //輸出結果
for(int i=0;i<n;i++){
printf("<%d,%d>: ",v+1,i+1);
int p=pre[i];
if(p!=-1){ //若可達輸出最短路徑
printf("%d ",dist[i]); //輸出最短距離
printf("%d",i+1); //根據前趨逆向輸出最短路徑
while(p!=v){
printf("<--%d",p+1);
p=pre[p];
}
printf("<--%d",v+1);
}
else{ //若不可達則輸出“inf”
printf("inf");
}
printf("\n");
}
}
int main(){
printf("Please enter the number of n and e:");
scanf("%d%d",&n,&e);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
cost[i][j]=max; //初始化為max
int start,end,dut;
for(int i=0;i<e;i++){
scanf("%d%d%d",&start,&end,&dut); //輸入邊的始點,終點和權值
start--;
end--; //結點號與存儲的下標相差1
cost[start][end]=dut;
}
int v=0;
Dijkstra(v); //以頂點1(即下標為0)為原點v
return 0;
}