最短路径(Dijkstra算法)
- 基本概念:
1)最短路径:非带权图——边数最少的路径; 带权图——边上的权值之和最少的路径
- 基本思想:
1)
v:源点
S:已经生成最短路径的终点
w<v, vi>:从顶点 v 到顶点 vi 的权值
dist(v, vi):表示从顶点 v 到顶点 vi 的最短路径长度
2)
算法:Dijkstra算法
输入:有向网图 G=(V,E)
源点 v
输出:从 v 到其他“所有顶点”的最短路径
1. 初始化:集合S = {v};
dist(v, vi) = w<v, vi>, (i=1...n);
2. 重复下述操作直到 S == V//所有顶点都进来了
2.1 dist(v, vk) = min{dist(v, vj), (j=1...n)};
2.2 S = S + {vk};
2.3 dist(v, vj)=min{dist(v, vj),dist(v, vk) + w<vk, vj>};
//更新数据
- 存储结构:
1)采用邻接矩阵
a)对称
b)不能到达用正无穷
2)
-
运行实例:
1)整型数组dist[n]:存储当前最短路径的长度
2)字符串数组path[n]:存储当前的最短路径,即顶点序列
3)
4)
5)
6)
-
C实现片段:
void Dijkstra(MGraph *G, int v) /*从源点v出发*/
{
int i, k, num, dist[MaxSize]; char *path[MaxSize];
for (i = 0; i < G->vertexNum; i++)
{
dist[i] = G->edge[v][i];
path[i] = G->vertex[v]+G->vertex[i];
}
for (num = 1; num < G->vertexNum; num++)
{
for (k = 0, i = 0; i < G.vertexNum; i++)
{
if ((dist[i] != 0) && (dist[i] < dist[k]))
{
k = i;
}
}
printf("%s %d ",path[k], dist[k]);
for (i = 0; i < G->vertexNum; i++)
{
if (dist[i] > dist[k] + G->edge[k][i])
{
dist[i] = dist[k] + G->edge[k][i];
path[i] = path[k] + G->vertex[i];
}
}
dist[k] = 0;
}
}
时间复杂度:O(n^2)
-
最短路径不唯一,但是路径总权值最小,且相等。
-
例题:
【问题描述】
假设以一个带权无向图表示某一区域的公交线路网,图中顶点代表一些区域中的重要场所,弧代表已有的公交线路,弧上的权表示该线路上的票价(或搭乘所需时间)<权值>,试设计一个交通指南系统,指导前来咨询者以最低的票价或最少的时间从区域中的某一场所到达另一场所。现在输出1到第n个场所的最低票价。
实验要求:利用Dijkstra算法求最低票价
【输入形式】
首先,输入一个n,表示有n(编号1-n)个场所,m表示有m条边,接下来m行,每行输入a,b,c三个正整数(以空格分隔)。表示a,b之间有票价c
(这是一张<无向图>)。
(2<=n<=100, 1<=m<=1000, 1<=a,b<=n, 1<=c<=100)
【输出形式】
为简化输出,只输出场所1到第n个场所中的最低票价。
因题目要求,改变上面的部分代码
//最短路径—— Dijiksra
//邻接矩阵 无向图
#include<stdio.h>
#include<stdlib.h>
#define Max 1001
#define MaxSize 100
//1)图的数据类型
typedef struct
{
int vertex[MaxSize];//存储点的信息
int edge[MaxSize][MaxSize];//存储便之间的邻接关系
int vertexNum,edgeNum;//点的个数,边的个数
}MGraph;
//2)构造一个图
MGraph CreatGraph(int n,int m)
{
MGraph G;
int i,j,a,b,c;
//点 边
G.vertexNum=n;
G.edgeNum=m;
//点的信息
for(i=1;i<=G.vertexNum;i++)
{
G.vertex[i]=i;
}
//边邻接关系的初始化
for(i=1;i<=G.vertexNum;i++)
{
for(j=1;j<=G.vertexNum;j++)
{
if(i==j)
{
G.edge[i][j]=0;
}
else
{
G.edge[i][j]=Max;
}
}
}
//输入m行边的信息
for(i=1;i<=G.edgeNum;i++)
{
scanf("%d %d %d",&a,&b,&c);
G.edge[a][b]=c;
G.edge[b][a]=c;//无向图
}
return G;
}
//3)核心算法
void Dijkstra(MGraph G, int v,int n)/*从源点v出发*/
{
int i, k, num, dist[n],d[n];
//初始化
for (i = 2; i <=G.vertexNum; i++)
{
dist[i] = G.edge[v][i];//存储当前最短路径的长度
}
for (num = 1; num < G.vertexNum; num++)
{
for (k = 2, i = 2; i <=G.vertexNum; i++)
{
if(dist[k]==0)
{
for(k=2;k<=G.vertexNum;k++)
{
if((dist[k]==0)&&(dist[k+1]!=0))
{
k++;
break;
}
}
}
if ((dist[i] != 0) && (dist[i] < dist[k]))
{
k = i;
}
}
for (i = 2; i <=G.vertexNum; i++)
{
if (dist[i] > dist[k] + G.edge[k][i])
{
dist[i] = dist[k] + G.edge[k][i];
}
}
d[k]=dist[k];
dist[k] = 0;
}
printf("%d",d[G.vertexNum]);
}
int main()
{
int n,m;//场所,边
scanf("%d %d",&n,&m);
//创造
MGraph G;
G=CreatGraph(n,m);
//Dijksra
int v;
v=1;
Dijkstra(G,v,n);
return 0;
}