演算法之單源最短路徑問題
阿新 • • 發佈:2018-12-18
1.問題描述:給出一個有向圖G,圖中的每一條邊都有一個非負邊權,要求找出從圖的源頂點s到目標頂點t之間的最短路徑。
例圖:從左到右從上到下,序號從0開始依次增大,即頂點個數n=11,A=s,E=t
2.問題分析:
(1)分支限界法:
演算法從G的源點s和空佇列開始。結點s被擴充套件之後,他的兒子結點2,3,4被一次插入隊列當中。然後取出隊頭元素,進行下一步擴充套件。保證每一次擴充套件時,源到當前節點的和都是最小的。具體的解空間圖如下:
演算法過程
演算法先從源節點s開始擴充套件,3個子結點2,3,4被插入到隊列當中,如下圖所示。
取出結點2,它有3個子樹。結點2沿邊f擴充套件到3時,路徑長度為5,而結點3的當前路徑為3(s->6),沒有得到優化,該子樹被剪掉。.結點2沿邊d,e擴充套件值5,6時,將他們加入優先佇列,如圖
取出頭結點3,它有兩個子樹。結點3沿f邊擴充套件到結點6時,該路徑長度為12,而結點6的當前路徑為4,該路徑沒有被優化,該子樹被剪枝。結點3沿g擴充套件到7時,將7加入到優先佇列。如下如所示
重複上面操作直到佇列為空。s到各個結點的最短路徑。
(2)Dijkstra演算法:
將圖G中所有的頂點V分成兩個頂點集合S和T。以v為源點已經確定了最短路徑的終點併入S#include <iostream>
using namespace std;
#define NoEdge -1 //表示無邊
#define MAXVALUE 10000
int n=11;//頂點個數
int dist[11];//記錄從某源頂點v到各頂點的最短距離
int s[11];//已經確定了最短路徑的終點
int t[11];//尚未確定到源點v最短路徑的頂點集合
int prev[11];//記錄每個頂點最短路徑上的前驅頂點,根據該陣列可以找到任何一個頂點到達源頂點v的最短路徑
int e[11][11];//記錄頂點之間邊的權值(-1表示無邊)
int FindIndexOfMin(int dist[])//找到最短的路徑
{
int index=0;
int minc=MAXVALUE;
for(int i=0; i<n; i++)
{
if(minc>dist[i]&&dist[i]!=NoEdge&&s[i]==0)
{
minc=dist[i];
index=i;
}
}
return index;
}
bool isEmpty(int t[])//判斷未確定最短路徑的頂點集合t是否為空
{
for(int i=0; i<n; i++)
if(t[i]==1)return false;
return true;
}
void Init()
{
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
e[i][j]=-1;
e[0][1]=5;
e[0][2]=3;
e[1][3]=1;
e[1][4]=3;
e[1][5]=6;
e[2][4]=8;
e[2][5]=7;
e[2][6]=6;
e[3][7]=6;
e[3][8]=8;
e[4][7]=3;
e[4][8]=5;
e[5][8]=3;
e[5][9]=3;
e[6][8]=8;
e[6][9]=4;
e[7][10]=3;
e[8][10]=2;
e[9][10]=2;
}
void ShortestPath2(int v)//分支限界法
{
//活結點表x[n],各頂點到源頂點最短距離dis[n],最短路徑的前驅頂點pre[n]
int x[n],dis[n],pre[n];
for(int i=0; i<n; i++) //將與源頂點v相連的頂點加入活結點表
{
if(e[v][i]!=NoEdge)
{
x[i]=1;
pre[i]=v;
}
else
{
x[i]=0;
pre[i]=i;
}
dis[i]=e[v][i];
}
while(true)
{
int index=NoEdge;
for(int i=0; i<n; i++)//從當前活結點表取出一個新的擴充套件結點
{
if(x[i]==1)
{
index=i;
x[i]=0;
break;
}
}
if(index==NoEdge)break;//活結點表空則退出迴圈
for(int i=0; i<n; i++)
{//判斷經過該擴充套件結點到達它的子結點的最短路徑是否比原記錄的最短路徑小
if(e[index][i]!=NoEdge&&(dis[index]+e[index][i]<dis[i]||dis[i]==NoEdge))
{
x[i]=1;
dis[i]=dis[index]+e[index][i];
pre[i]=index;
}
}
}
for(int i=0; i<n; i++)
cout<<dis[i]<<" ";
cout<<endl;
for(int i=0; i<n; i++)
cout<<pre[i]<<" ";
cout<<endl;
}
void ShortestPath(int v)//Dijkstra演算法
{
for(int i=0; i<n; i++)
{
prev[i]=i;
dist[i]=e[v][i];
t[i]=1;
s[i]=0;
}
int m=n;
while(--m>0)//(isEmpty(t)==false)
{
int index=FindIndexOfMin(dist);
s[index]=1;
t[index]=0;
if(prev[index]==index)prev[index]=v;
for(int i=0; i<n; i++)
{
if(t[i]==1&&e[index][i]!=NoEdge&&dist[index]!=NoEdge&&(e[index][i]+dist[index]<dist[i]||dist[i]==NoEdge))
{
dist[i]=e[index][i]+dist[index];
prev[i]=index;
}
}
}
}
int main()
{
Init();
ShortestPath2(0);
/*for(int i=0; i<n; i++)
cout<<prev[i]<<" ";
cout<<endl;
for(int i=0; i<n; i++)
cout<<dist[i]<<" ";
cout<<endl;*/
}