單源點的最短路徑:給定帶權有向圖G和源點v,求從v到G中其余各頂點的最短路徑。
求解方法:Dijkstra算法,基本思想是按路徑長度遞增的次序產生最短路徑的算法。若S為已求得最短路徑的終點的集合,那么下一條最短路徑(設其終點為x)或者弧(v,x),或者是中間只經過S中的頂點而最后到達頂點x的路徑。
廣度優先搜索的思想:
假設從圖中某頂點v出發,在訪問了v之后依次訪問v的各個未曾訪問過的鄰接點,然后分別從這些鄰接點出發依次訪問它們的鄰接點,並使“先被訪問的頂點的鄰接點”先於“后被訪問的頂點的鄰接點”被訪問,直至圖中所有已被訪問的頂點的鄰接點都被訪問到。由於在訪問的過程中,要按照訪問順序來訪問已訪問頂點的鄰接點,因此蘊含了一種“先進先出”的思想,可以使用隊列來完成這個任務。
#include <iostream> #include <queue> #include <string.h> #include <stdio.h> using namespace std; const int N=16; int shortest_path(int G[N][N]) { int step[N]; //從源點出發,每個結點最快第幾步到達 int stepchoice[N]; //從源點出發,最短路徑的走法有幾種 memset(step,0,sizeof(int)*N); memset(stepchoice,0,sizeof(int)*N); //廣度優先搜索遍歷圖 queue<int> q; //使用隊列數據結構,存儲當前要搜索的結點 stepchoice[0]=1; q.push(0); //從源點開始遍歷圖 while(!q.empty()) { int from=q.front(); //當前要搜索結點為隊首元素 q.pop(); int s=step[from]+1; //源點到from鄰接點的最短距離 for(int i=1;i<N;i++) //遍歷from的所有鄰接點,0是源點不遍歷(因為0是源點,走的過程中不可能倒回去) { if(G[from][i]==1) //連通 { if((step[i]==0)||(s<step[i])) { step[i]=s; stepchoice[i]=stepchoice[from]; //如果之前i已經被搜索到,但是最短距離被修改,那么相應i的鄰接點們也要重新被遍歷 //如果之前i未被搜索到,那么要繼續搜索它的鄰接點們 q.push(i); } else if(step[i]==s) //發現相同的路徑 { stepchoice[i]+=stepchoice[from]; } } } } return stepchoice[N-1]; } int main() { int G[N][N]; memset(G,0,sizeof(int)*N*N); //初始化矩陣 G[0][1]=G[0][4]=1; G[1][0]=G[1][2]=G[1][5]=1; G[2][1]=G[2][3]=G[2][6]=1; G[3][2]=G[3][7]=1; G[4][0]=G[4][5]=1; G[5][1]=G[5][4]=G[5][6]=G[5][9]=1; G[6][2]=G[6][5]=G[6][7]=G[6][10]=1; G[7][3]=G[7][6]=1; G[8][9]=G[8][12]=1; G[9][5]=G[9][8]=G[9][10]=G[9][13]=1; G[10][6]=G[10][9]=G[10][11]=G[10][14]=1; G[11][10]=G[11][15]=1; G[12][8]=G[12][13]=1; G[13][9]=G[13][12]=G[13][14]=1; G[14][10]=G[14][13]=G[14][15]=1; G[15][11]=G[15][14]=1; printf("最短路徑條數:%d\n",shortest_path(G)); return 0; }