————————————最短路徑————————————
問題抽象:在帶權有向圖中A點(源點)到達B點(終點)的多條路徑中,尋找一條各邊權值之和最小的路徑,即最短路徑。
兩種常見的最短路徑問題:
Dijkstra算法思想
① 初始化:
● 將源點v0加到S中,即S[v0] = true;
● 將v0到各個終點的最短路徑長度初始化爲權值,即D[i] = G.arcs[v0][vi],(vi∈V − S);
● 如果v0和頂點vi之間有弧,則將vi的前驅置爲v0,即Path[i] = v0,否則Path[i] = −1。
② 選擇下一條最短路徑的終點vk,使得:
D[k] = Min{D[ i ]|vi∈V − S}
③ 將vk加到S中,即S[vk] = true。
④ 更新從v0出發到集合V − S上任一頂點的最短路徑的長度,同時更改vi的前驅爲vk。
若S[i]=false 且 D[k]+G.arcs[k][i]<D[i],則D[i]=D[k]+ G.arcs[k][i]; Path [i]=k;。
⑤ 重複②~④ n − 1次,即可按照路徑長度的遞增順序,逐個求得從v0到圖上其餘各頂點的最短路徑。
Dijkstra算法示例
Dijkstra算法的代碼實現(c++)
實驗內容與要求
根據輸入的圖形,輸入起點和終點,求出最短路徑和最短路徑的長度。
具體步驟
1. 編寫一段代碼,接收鍵盤的輸入定點的數量,並以輸入的整數對作爲邊來建
立圖形的鄰接矩陣(無向權重圖)。
例如: 5,6,12
表示定點5 和定點6 間有邊,邊的權重爲12。
2. 打印出鄰接矩陣。
3. 輸入起點和終點。
4. 打印最短路徑和最短路徑的長度
5. 樣例:數據測試測試數據:
/*
6 8
1 2 3 4 5 6
1 3 5
1 4 30
2 1 2
3 2 15
3 6 7
5 4 4
6 4 10
6 5 18
1
5
*/
代碼如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
//————圖的鄰接矩陣存儲表示————
#define MaxInt 0x3f3f3f3f //表示權值的無窮
#define MVNum 100 //最大頂點數,應由用戶定義
#define OK 1
typedef int Status;
typedef char VerTexType; //頂點的數據類型
typedef int ArcType; //邊的權值類型
bool S[MVNum]; //數組S:記錄v0到vi是否確定最短路徑,即已求出最短路徑的終點的集合
int D[MVNum]; //數組D:記錄v0到vi當前最短路徑的長度
int Path[MVNum]; //記錄v0到vi當前最短路徑上vi的直接前驅序號
typedef struct{
VerTexType vexs[MVNum]; //頂點表
ArcType arcs[MVNum][MVNum]; //鄰接矩陣
int vexnum,arcnum; //圖的當前頂點數和邊數
}AMGraph;
Status LocateVex(AMGraph G,VerTexType v){
int i;
for(i=0;i<G.vexnum;i++){
if(v==G.vexs[i])
return i;
}
}
Status CreateUDN(AMGraph &G){ //採用鄰接矩陣表示法,創建無向網
Status i,j,k,w;
VerTexType v1,v2;
printf("請輸入定點和邊的數目:");
scanf("%d %d",&G.vexnum,&G.arcnum); // 總頂點數,總邊數
printf("請依次輸入頂點:\n");
for(i=0;i<G.vexnum;i++)
cin>>G.vexs[i];
for(i=0;i<G.vexnum;i++) //鄰接矩陣初始化爲無窮大
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=MaxInt;
puts("請依次輸入邊的起點終點以及權值:");
for(k=0;k<G.arcnum;k++){ //構造鄰接矩陣
cin>>v1>>v2>>w; //輸入邊的頂點及權值
i=LocateVex(G,v1);
j=LocateVex(G,v2);
G.arcs[i][j]=w; //邊<v1,v2>的權值置位w
G.arcs[j][i]=w;
}
return OK;
}
//用Dijkstra算法求有向網G的v0頂點到其餘頂點的最短路徑
void ShortestPath_DIJ(AMGraph G,int v0){
int v,w,n=G.vexnum; //n爲G中頂點的個數
for(v=0;v<n;++v){ //n個頂點依次初始化
S[v]=false; //S初始爲空集
D[v]=G.arcs[v0][v]; //將v0到各個終點的最短路徑長度初始化
if(D[v]<MaxInt) Path[v]=v0; //v0和v之間有弧,將v的前驅置爲v0
else Path[v]=-1; //如果v0和v之間無弧,則將v的前驅置爲-1
}
S[v0]=true; //將v0加入S
D[v0]=0; //源點到源點的距離爲0
//——————開始主循環,每次求得v0到某個頂點v的最短路徑,將v加到S集—————
for(int i=1;i<n;++i){ //對其餘n-1個頂點,依次進行計算
int min=MaxInt;
for(w=0;w<n;++w)
if(!S[w]&&D[w]<min)
{v=w; min=D[w];} //選擇一條當前的最短路徑,終點爲v
S[v]=true; //將v加入S
for(w=0;w<n;++w) //更新從v0出發到集合V-S上所有頂點的最短路徑長度
if(!S[w]&&(D[v]+G.arcs[v][w]<D[w])){
D[w]=D[v]+G.arcs[v][w]; //更新D[w]
Path[w]=v; //更改w的前驅爲v
}
}
}
//打印路徑
void Print_Path(AMGraph G,int v0,int v1){
int cnt=0,T=v1,st[MVNum];
st[0]=v1;
while(Path[v1]!=-1){
st[++cnt]=Path[v1];
v1=Path[v1];
}
for(int i=cnt;i>=0;i--){
printf("%c ",G.vexs[st[i]]);
}
printf("該路徑的長度爲:%d",D[T]);
}
int main(){
int i,j,v0,v1;
char s;
AMGraph G;
CreateUDN(G);
puts("構成的鄰接矩陣爲:");
for(i=0;i<G.vexnum;i++){
for(j=0;j<G.vexnum;j++)
printf("%d ",G.arcs[i][j]);
printf("\n");
}
puts("請輸入起點:");
cin>>s;
v0=LocateVex(G,s);
ShortestPath_DIJ(G,v0);
puts("請輸入你想打印到哪個點的路徑:");
cin>>s;
v1=LocateVex(G,s);
Print_Path(G,v0,v1);
return 0;
}
輸入:
6 8
1 2 3 4 5 6
1 3 5
1 4 30
2 1 2
3 2 15
3 6 7
5 4 4
6 4 10
6 5 18
1
5
輸出