1.Dijkstra
1) 適用條件&范圍:
a) 單源最短路徑(從源點s到其它所有頂點v);
b) 有向圖&無向圖(無向圖可以看作(u,v),(v,u)同屬於邊集E的有向圖)
c) 所有邊權非負(任取(i,j)∈E都有Wij≥0);
2) 算法描述:
在帶權圖中最常遇到的問題就是,尋找兩點間的最短路徑問題。
解決最短路徑問題最著名的算法是Djikstra算法。這個算法的實現基於圖的鄰接矩陣表示法,它不僅能夠找到任意兩點的最短路徑,還可以找到某個指定點到其他所有頂點的最短路徑。
此算法的基本思想是:
1>選中指定的頂點,列出此頂點到其他的頂點的權值,不相鄰的為無窮大
2>從以上權值中選出最小值,此最小值就是起始點到對應頂點的最短路徑,並標記這個對應頂點
3> 將起始點到其他未標記的頂點的直接距離與起始點到剛才標記頂點加上標記頂點到其他頂點距離的和比較,如果 后者小,則更新對應的權值。
4> 轉2
程序代碼如下:
#include <iostream>
#include <iomanip>
using namespace std;
#include "Graph.h"
void main()
{
int i, n;
cout << "輸入你所輸入的有向帶權圖的頂點個數: ";
cin >> n;
adjmatrix g;
InitMatrix(g);
CreateMatrix(g);
cout << "你輸入的有向帶權圖的鄰接矩陣表示為: " << endl;
PrintMatrix(g, n);
int * d = new int [n];
edgenode ** path = new edgenode * [n];
cout << "請輸入你要輸入的源點: ";
cin >> i;
Dijkstra(g, d, path, i, n);
PrintPath(d, path, i, n);
}
//***********Graph.h**********************
#define MaxVerNum 20
#define MaxValue 10000
typedef int adjmatrix[MaxVerNum][MaxVerNum]; //鄰接矩陣的類型定義
typedef struct Node
{
int adjvex;
struct Node * next;
}edgenode; //指針數組path[]基類型定義
//初始化鄰接矩陣表示的有向帶權圖
void InitMatrix(adjmatrix G)
{
int i, j;
for(i = 0; i < MaxVerNum; i++)
for(j = 0; j < MaxVerNum; j++)
G[i][j] = MaxValue;
}
//建立鄰接矩陣表示的有權帶向圖(即通過輸入圖的每條邊建立圖的鄰接矩陣)
void CreateMatrix(adjmatrix G)
{
int i, j, x;
cout << "請輸入頂點和相應的權值: " << endl;
cin >> i >> j >> x;
while(i != -1)
{
G[i][j] = x;
cin >> i >> j >> x;
}
}
//輸出鄰接矩陣表示的有向帶權圖(即輸出圖的每條邊)
void PrintMatrix(adjmatrix G, int n)
{
int i, j;
for(i = 0; i < n; i++)
{
for(j = 0; j < n; j++)
{
if(G[i][j] == MaxValue)
cout << setiosflags(ios::left) << setw(5) << "Inf";
else
cout << setiosflags(ios::left) << setw(5) << G[i][j];
}
cout << endl;
}
}
void Path(edgenode * path[], int m, int j)
{
edgenode * p, * q, *s;
p = path[j];
while(p != NULL)
{
path[j] = p->next;
delete p;
p = path[j];
}
p = path[m];
while(p != NULL)
{
q = new edgenode;
q->adjvex = p->adjvex;
if(path[j] == NULL)
path[j] = q;
else
s->next = q;
s = q;
p = p->next;
}
q = new edgenode;
q->adjvex = j;
q->next = NULL;
s->next = q;
}
//求最短路徑的Dijkstral算法
void Dijkstra(adjmatrix GA, int dist[], edgenode *path[], int i, int n)
{
int j, k, w, m;
bool * s = new bool[n];
for(j = 0; j < n; j++)
{
if(j == i)
s[j] = true;
else
s[j] = false;
dist[j] = GA[i][j];
if(dist[j] < MaxValue && j != i)
{
edgenode * p1 = new edgenode;
edgenode * p2 = new edgenode;
p1->adjvex = i;
p2->adjvex = j;
p2->next = NULL;
p1->next = p2;
path[j] = p1;
}
else
path[j] = NULL;
}
for(k = 1; k <= n-2; k++)
{
w = MaxValue;
m = i;
for(j = 0; j < n; j++)
if(s[j] == false && dist[j] < w)
{
w = dist[j];
m = j;
}
if(m != i)
s[m] = true;
else
break;
for(j = 0; j < n; j++)
if(s[j] == false && dist[m] + GA[m][j] < dist[j])
{
dist[j] = dist[m]+GA[m][j];
Path(path, m, j);
}
}
delete []s;
}
//輸出從源點到每個頂點的最短路徑及長度的函數
void PrintPath(int dist[], edgenode * path[], int i, int n)
{
int j;
for(j = 0; j < n; j++)
{
if(i != j)
{
cout << "頂點v" << i << "到頂點v" << j << "的最短路徑的長度為 "
<< dist[j] << ", 最短路徑為: ";
edgenode * p = path[j];
while(p != NULL)
{
cout << setw(4) << p->adjvex;
p = p->next;
}
cout << endl;
}
}
}
程序運行結果:
輸入你所輸入的有向帶權圖的頂點個數: 6
請輸入頂點和相應的權值:
0 1 10
0 2 12
1 3 16
1 4 25
2 0 4
2 1 3
2 3 12
2 5 8
3 4 7
5 3 2
5 4 10
-1 2 3
你輸入的有向帶權圖的鄰接矩陣表示為:
Inf 10 12 Inf Inf Inf
Inf Inf Inf 16 25 Inf
4 3 Inf 12 Inf 8
Inf Inf Inf Inf 7 Inf
Inf Inf Inf Inf Inf Inf
Inf Inf Inf 2 10 Inf
請輸入你要輸入的源點: 0
頂點v0到頂點v1的最短路徑的長度為 10, 最短路徑為: 0 1
頂點v0到頂點v2的最短路徑的長度為 12, 最短路徑為: 0 2
頂點v0到頂點v3的最短路徑的長度為 22, 最短路徑為: 0 2 5 3
頂點v0到頂點v4的最短路徑的長度為 29, 最短路徑為: 0 2 5 3 4
頂點v0到頂點v5的最短路徑的長度為 20, 最短路徑為: 0 2 5
Press any key to continue
轉自:http://blog.sina.com.cn/s/blog_51b6521b0100k96c.html