數據結構篇之最短路徑

————————————最短路徑————————————

問題抽象:帶權有向圖A點(源點)到達B點(終點)的多條路徑中,尋找一條各邊權值之和最小的路徑,即最短路徑。

兩種常見的最短路徑問題:

一、 單源最短路徑Dijkstra(迪傑斯特拉)算法

二、所有頂點間的最短路徑Floyd(弗洛伊德)算法

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[ ]|vi∈V  S}

vk加到S中,即S[vk] = true

更新v0出發到集合 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;

⑤ 重複②~④ − 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

輸出 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章