1. 程式人生 > >【ACM】帶權有向圖單源最短路徑(Dijkstra演算法)

【ACM】帶權有向圖單源最短路徑(Dijkstra演算法)

最短路徑的第一類問題
求從單個源點到其餘各頂點的最短路徑。這是一種貪心策略,不可以存在負權邊。

演算法簡介
給定帶權有向圖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]; } } }