貪心法之最短路徑之Dijkstra算法

A,問題描述:假如A地爲倉庫,要向不同的售貨點供貨,爲了節約成本,因此要計算出從A點出發通向每個售貨點的最短距離路徑。也就是求解圖中頂點A到圖中其它各頂點的最短路徑,圖中每個頂點代表一個售貨點。Dijkstra算法就是用於求解帶權有向圖中從一點出發到其它各頂點的最短路徑的算法。下面詳細介紹該算法。
B,Dijkstra算法:該算法用於求解從一個頂點出發到其餘各頂點的最短路徑的算法解決的是有向圖中最短路徑的問題,其主要特點是以起始點爲中心向外層層擴展,直到擴展到終點爲止。貪心法思想體現在每次優先選取離出發點O距離最近的點,然後再更改O點到其它各頂點的距離。
C,算法處理過程:
1)假設帶權有向圖G的頂點集合爲V,起始點爲V0;
2)初始S={V0},T=V-S={其餘頂點},其中集合S表示已經計算出最短距離的頂點,T是還沒計算的剩餘頂點;
3)初始化V0到其餘各點的距離,d(v0,vi)代表v0到vi的最短距離,按如下規則:即;
4)若V0可以直接到達某個頂點vi,則將邊的權值賦給d(v0,vi),否則d(v0,vi)=∞;
5)從T中選取一個與S中頂點有關聯(直接相連)且權值最小的頂點w(這裏用到了貪心法思想),加入到S中;
6)以w作爲中間點,若V0到T中某個頂點vi距離變短,則修改d(v0,vi)的值;
7)重複5)和6)直到T爲空,即計算完了所有頂點,算法結束。
下圖爲Dijkstra算法求解最短路徑的過程舉例:
貪心法之最短路徑之Dijkstra算法

D,算法實現:
#include"iostream"
usingnamespace std;
#defineMAXVEX 50//圖中最大節點數
#defineMAXIMUN 65535//定義爲最大數
typedefstruct //定義鄰接矩陣的數據結構
{
charvexs[MAXVEX];
intedges[MAXVEX][MAXVEX];
int vexNum,adgeNum;//分別表示圖中節點個數和邊的條數
}AGraph;
intmain()
{
voidcreateG(AGraph *);
voidprintPath(AGraph *, int[], int);
voiddijkstra(AGraph *, int, int[], int[][MAXVEX]);
intd[MAXVEX][MAXVEX], prior[MAXVEX];
for(int i =0; i < MAXVEX; ++i)
prior[i] =-1;
AGraphg;
createG(&g);
//初始化d
for(int m =0; m < g.vexNum; ++m)
for(int n =0; n < g.vexNum; ++n)
{
d[m][n] =MAXIMUN;
}
intstart;
cout<<"請輸入起始點start:";
cin>>start;
dijkstra(&g, start, prior, d);
while(true)
{
intnode;
cout<<"\n請輸入頂點"<<start<<"所要到達的頂點i:";
cin>>node;
printPath(&g, prior, node);
cout<<g.vexs[node]<<endl;
cout<<"路徑總長度爲:"<<d[start][node]<<endl;
}
return0;
}
//輸出到某個頂點node的路徑
voidprintPath(AGraph *g, int prior[], int node)
{
intstack[MAXVEX], bottom, top;
top = bottom= -1;
while(prior[node] != -1)
{
stack[++top]= prior[node];
node =prior[node];
}
intpath;
while(top> bottom)
{
path =stack[top--];
cout<<g->vexs[path]<<"->";
}
}
//Dijkstra算法求解最短路徑
//g爲帶權有向圖,start爲起始點
//prior保存從start到vi的路徑中vi的前一個節點的下標
//d存放start到其餘各頂點的最短路徑值
voiddijkstra(AGraph *g, int start, int prior[], intd[][MAXVEX])
{
intS[MAXVEX], T[MAXVEX];//S爲已經計算的頂點集合,T是剩餘的頂點集合
int n =0;//表示已加入的頂點個數
//初始化d,S和T
for(int i =0; i < g->vexNum; ++i)
{
T[i] =i;//保存圖中個頂點編號
//將與start直接相連的邊的權值賦給d
if(g->edges[start][i] < MAXIMUN)
{
d[start][i] =g->edges[start][i];
prior[i] =start;
}
}
d[start][start] = 0;//修改起始頂點到它自身的距離爲0
S[0] =start;//將start加入集合S
++n;
T[start] =-1;//將start從集合T中去掉,這裏設置該位置爲-1表示去掉
for(int j =1; j < g->vexNum; ++j)
{
int indexK,indexP, mintemp;//
//下面用貪心法思想尋找最優加入頂點
mintemp =MAXIMUN;
for(int p =0; p < n; ++p)
{
for(int k =0; k < g->vexNum; ++k)
{
if((T[k] !=-1) && (g->edges[S[p]][T[k]] < MAXIMUN) &&(mintemp > g->edges[S[p]][T[k]]))
{
mintemp =g->edges[S[p]][T[k]];
indexP =S[p];
indexK =T[k];
}
}
}
S[n++] =indexK;
T[indexK] =-1;
if(d[start][indexK] > (d[start][indexP] +g->edges[indexP][indexK]))
d[start][indexK] = d[start][indexP] +g->edges[indexP][indexK];//修改start與新加入的頂點的距離
//以indexK作爲中間頂點修改start到剩餘頂點的距離
for(int q =0; q < g->vexNum; ++q)
if((T[q] !=-1) && (g->edges[start][q] >g->edges[start][indexK] + g->edges[indexK][q]))
{
d[start][q] =g->edges[start][indexK] + g->edges[indexK][q];
prior[q] =indexK;
}
}
}
voidcreateG(AGraph *g)//創建無向網
{
int vNum,aNum;//分別代表要創建的圖的節點數和邊數
int start,end;//start->end表示節點start和end之間有一條邊
intweight;//邊的權重
cout<<"請輸入圖中節點的個數和邊的條數:";
cin>>vNum>>aNum;
printf("\n請輸入%d個節點的信息:", vNum);
//創建節點
for(int i =0; i < vNum; ++i)
{
cin>>g->vexs[i];
}
cout<<"這裏輸出節點編號及其存儲的節點信息"<<endl;
for(int k =0; k < vNum; ++k)
cout<<k<<":"<<g->vexs[k]<<"";
cout<<endl;
//初始化無向圖的邊信息
for(int m =0; m < vNum; ++m)
for(int n =0; n < vNum; ++n)
{
g->edges[m][n] = MAXIMUN;
}
//創建無向圖的邊信息
for(int j =0; j < aNum; ++j)
{
cout<<"\n請輸入第"<<j+1<<"條邊的start和end節點和邊的權重weight:";
cin>>start>>end>>weight;
g->edges[start][end] = weight;
g->edges[end][start] = weight;
}
//初始化vexNum和adgeNum
g->vexNum= vNum;
g->adgeNum= aNum;
}
運行結果:
貪心法之最短路徑之Dijkstra算法

E,複雜度分析
時間複雜度:我們分析dijkstra()方法的時間複雜度,算法需要計算從start出發到其餘各頂點的最短距離,需要n次,而每次查找最優加入頂點用了兩層循環,所以上述實現時間複雜度爲O(n^3)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章