定义
所谓最短路径问题是指:如果从图中某一顶点(源点)到达另一顶点(终点)的路径可能不止一条,如何找到一条路径使得沿此路径上各边的权值总和(称为路径长度)达到最小。
Dijkstra(迪杰斯特拉)算法
他的算法思想是按路径长度递增的次序一步一步并入来求取,是贪心算法的一个应用,用来解决单源点到其余顶点的最短路径问题。
//利用狄克斯特拉(Dijkstra)算法求上图中0结点到其它结点的最短路径,单源到单终点
//思想:某点到其他点的最短距离
//将N=(V,E)的所有顶点分成2个组合,第一组S:已经求出最小距离的点,起初只有v0,第二组:尚且为求出最短路径的终点集合
//按照各个顶点与v0间距递增的次序,逐个将V-S中的点加入S中,过程中要保持从v0到集合S各顶点的距离长度始终不大于到集合V-S中各顶点的距离长度
//算法辅助:带权的邻接矩阵,源点是v0
// 一维数组S[i]:记录从v0到vi是否已经被确定为最短路径长度,true表示确定
// 一维数组path[i];记录从源点到vi当前最短路径上的前驱:初始化:如果v0到vi有弧,则path[i]=v0,否则为-1
// 一维数组D[i]:记录从源点到vi的当前最短路径长度,初始化如果v0到vi有弧,则D[i]=弧上的权值,否则为无穷大
//S每加入一个点,多一个中转点
//假设v0到vi原来最小路径为D[i],加入vk后,以vk为中转的路径长度为D[k]+G.arc[k][i],if(D[i]>D[i]+G.arc[k][i])->D[i]=D[i]+D.arc[k][i]
//1图的邻接矩阵表示法和邻接表创建无向图存储
#include<iostream>
using namespace std;
#define MaxNum 100 //最大顶点数
//1.1图的邻接矩阵表示法创建无向图存储
#define MaxInt 32767 //无穷
typedef char VerType;//数据类型
typedef int ArcType;//权值类型
//图结构类型
typedef struct {
VerType v[MaxNum];//顶点表
ArcType arc[MaxNum][MaxNum];//邻接矩阵
int vernum, arcnum; //点数,边数
}AMGraph;
//定位
int locate(AMGraph G, VerType v1) {
for (int i = 0; i < G.vernum; i++) {
if (G.v[i] == v1)
return i;
}
return -1;
}
//创建无向图
bool createUDN(AMGraph &G) {
cout << "Please input the vernum and arcnum" << endl;
cin >> G.vernum >> G.arcnum;
int i,j,p,q;
VerType v1, v2;
ArcType w;
//初始化点的名字
cout << "Please input the name of vernum in order " << endl;
for (i = 0; i < G.vernum; i++) cin >> G.v[i];
//初始化邻接矩阵
for (i = 0; i < G.vernum; i++) {
for (j = 0; j < G.vernum; j++) {
if (i != j)
G.arc[i][j] = MaxInt;
else
G.arc[i][j] = 0;
}
}
//开始操作,构造邻接表
cout << "Please input arcnum graph " << endl;
for (i = 0; i < G.arcnum; i++) {
cin >> v1 >> v2 >> w;
p = locate(G, v1); q = locate(G, v2);
G.arc[p][q] = w;
G.arc[q][p] = G.arc[p][q];
}
return true;
}
void show(AMGraph G) {
int i, j;
for (i = 0; i < G.vernum; i++) {
for (j = 0; j < G.vernum; j++) {
if (G.arc[i][j] == MaxInt) printf("INF\t");
else printf("%-3d\t", G.arc[i][j]);
}
cout << endl;
}
}
//Dijkstra展示
//利用递归,找到前驱等于自己的点,递归返回输出后继结点
void showCircle(AMGraph G,int path[], int v0, int u) {
if (u == v0) {
cout << G.v[u]<< " ";
return;
}
else
showCircle(G,path, v0, path[u]);
cout << G.v[u] << " ";
}
//算法辅助:带权的邻接矩阵,源点是v0
// 一维数组S[i]:记录从v0到vi是否已经被确定为最短路径长度,true表示确定
// 一维数组path[i];记录从源点到vi当前最短路径上的前驱:初始化:如果v0到vi有弧,则path[i]=v0,否则为-1
// 一维数组D[i]:记录从源点到vi的当前最短路径长度,初始化如果v0到vi有弧,则D[i]=弧上的权值,否则为无穷大
void ShortPath_DIJ(AMGraph G,int v0) {
bool *S = new bool[G.vernum];
int * path = new int[G.vernum];
int *D = new int[G.vernum];
memset(path, 0, sizeof(path));
//初始化
int i = 0, n = G.vernum,w=0;
for (i = 0; i < n; i++) {
S[i] = false; //点入集合的标志数组
D[i] = G.arc[v0][i];//v0到i点的最短路径长度,起初为弧上权值
if (D[i] < MaxInt) path[i] = v0;//与v0有弧
else path[i] = -1;
}
S[v0] = true;//将v0加入S
D[v0] = 0;
int v = -1;
//初始化结束,开始主循环,每次求得v0到某个点vi的最短路径,将vi加入S
for (i = 1; i < n; ++i) //列
{
ArcType min = MaxInt;
for (w = 0; w < n; ++w){ //行
if (!S[w] && D[w] < min) {
min = D[w];
v = w;//选择当前最短路径终点v
}
}
S[v] = true;//将v加入S中的标志
for (w = 0; w < n; ++w) {//更新从v0出发到V-S上所有的顶点的最短路径长度
if (!S[w] && (D[v] + G.arc[v][w] < D[w])) {
D[w] = D[v] + G.arc[v][w];
path[w] = v; //最短路径前驱是v
}
}
}
cout << "Please input the source and destination" << endl;
char ch1, ch2;
while (cin >> ch1 >> ch2) {
v = locate(G, ch1); w = locate(G, ch2);
showCircle(G,path,v,w );
cout << "length=" << D[w] << endl;
cout << endl;
cout << "Please input the source and destination" << endl;
}
delete[]S;
S = NULL;
delete[]path;
path = NULL;
delete[]D;
D= NULL;
}
int main() {
AMGraph G;
createUDN(G);
show(G);
ShortPath_DIJ(G,0);
}
我这里只是给代码实现,想动态地了解,推荐下面这篇的(有图片介绍)
https://blog.csdn.net/lbperfect123/article/details/84281300