【ACM】帶權有向圖單源最短路徑(Dijkstra演算法)
阿新 • • 發佈:2019-01-10
最短路徑的第一類問題
求從單個源點到其餘各頂點的最短路徑。這是一種貪心策略,不可以存在負權邊。
演算法簡介
給定帶權有向圖G和源點v0,求從源點v0到G中其餘各頂點的最短路徑。迪傑斯特拉演算法是對有權圖進行搜尋,但是如果引用於無權圖或者是權值相等的圖,就是廣度優先搜尋。(注意是有向圖)
演算法描述
對於網N=(V,E),將N中的頂點分成兩組:
第一組S:已求出的最短路徑的終點集合(初始時只含有v0)
第二組V-S:尚未求出最短路徑的終點集合(初始時為V-{v0})
演算法將按照各頂點與v0間的最短路徑長度遞增的次序,逐個將集合V-S中的頂點加入到集合S中。在這個過程中,總保持從v0到集合S中每一個頂點的路徑長度始終不大於到集合V-S中各頂點的路徑長度。
每當加入一個新的頂點到S集合中,對於V-S集合的頂點而言,多了一箇中轉結點
,因此要對V-S集合中的各個頂點的最短路徑的長度進行更新。
演算法程式碼
const int INF = 0x3f3f3f3f; //防止後面溢位,INF不能太大
const int maxn = 1000+5; //點的個數
bool visit[maxn]; //bool[i]表示是否確定過最短路徑
int map[maxn][maxn]; //用鄰接矩陣的方式來儲存圖
int distance[maxn]; //distance[i]表示v0到vi的最短路徑
void Dijkstra(int n,int beg) //beg表示源結點
{
for(int i=1;i<=n;i++)
{
distance[i] = map[beg][i];
visit[i] = false ;
}
visit[beg] = true;
distance[beg] = 0;
int v;
for(int i=2;i<=n;i++) //對其他的n-1個點進行操作
{
int Min = INF;
for(int j=1;j<=n;j++)
{
//遍歷左右結點,找到離當前源點的最短路徑
if(!visit[j] && distance[j] < Min)
{
v = j;
Min = distance [j];
}
}
visit[j] = true; //加入S集合
//鬆弛操作
for(int j=1;j<=n;j++)
{
if(!visit[j] && Min + map[v][j] < distance[j]) //利用這次加入的邊的Min進行對V-S集合distance的更新
//每一次MIn是S中最大的,因為之前加入的比後來的小
distance[j] = Min + map[v][j];
}
}
}