Dijkstra算法是解决有向带权图中最短路径的算法。
我用自己的语言解释Dijkstra算法的过程:
1.首先有一个有向带权图G=(V,E),V为顶点集合,E为边集合,用邻接矩阵map[n][n]来储存。
确定一个起始点origin,有一个辅助集合s,一开始将origin并入s中。
有一个辅助数组dist[n],dist[i]表示i距离origin的最短距离,初始化dist[i]=map[origin][i]。若不存在弧则相应等于无穷大
2.找一个顶点j,使顶点j存在于V-s中(即顶点j属于V但不属于s),并且dist[j]是所有V-s顶点中最小的一个,将顶点j并入s中;
3.遍历以顶点j为地点的弧<j,k>且k属于V-s中,如果dist[k] > dist[j] + weight<j,k>,则令dist[k]=dist[j] + weight<j,k>;
这一步相当于搭一个顶点j的顺风车。已知origin-j最短的距离是dist[j],若origin-k的(直接)距离大于
dist[j] + weight<j,k>,说明源点到顶点k的路径可以通过顶点j这条路而减少距离。
4.重复2,3步,直到s中包含了V中所有的顶点,结束算法。
代码:(C++实现)
#include <iostream>
#define MAX 999999
using namespace std;
const int n =5; //顶点数量
int map[n+1][n+1]; //有向图 邻接矩阵
int dist[n+1]={MAX}; //起点到其余顶点的距离
int s[n+1]={0}; //顶点集合
int pre[n+1]={0}; //每个顶点的直接前驱
void findMin(int origin)
{
int i,j;
for(j=1;j<=n;j++)
{
int minWeight=MAX; //dist[i]中最小权值
int minPoint =0; //最小权值的点
for(i=1;i<=n;i++)
{
if( !s[i] && dist[i]<= minWeight ) //寻找不在s中的最小权值的点
{
minWeight = dist[i];
minPoint = i;
}
}
if(minPoint==0) //如果没有找到,说明所有顶点都以并入s中
return ;
s[minPoint]=1; //将最小权值的点并中s中
//修改不在s中的其他顶点的dist值
for(i=1;i<=n;i++)
{
if( !s[i] && map[minPoint][i] != MAX)
if(dist[i] > dist[minPoint] + map[minPoint][i])
{
dist[i] = dist[minPoint] + map[minPoint][i];
pre[i] = minPoint; //将需要修改的顶点的直接前驱改为最小的权值点
}
}
}
}
void findPath(int i)
{
if(pre[i]==0) //表示i可能是起始点,也可能是和起始点不强连通的的点
{
if(dist[i] != MAX) //起始点
cout<<i;
else //与起始点不强连通的点
cout<<"不存在";
return ;
}
findPath(pre[i]);
cout<<"-"<<i;
}
int main()
{
int i,j;
int weight;
int origin; //起点顶点
//邻接矩阵初始化
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
map[i][j] = MAX;
cout<<"请输入权值"<<endl;
cout<<"格式:i j weight"<<endl;
cout<<"示例:1 2 2 即有一条弧<1,2>,权值为2,未输入数据则默认为无穷大"<<endl;
cout<<"结束时输入 0 0 0"<<endl;
cout<<"*************************"<<endl;
while(1)
{
cin>>i>>j>>weight;
if(i==0 && j==0 && weight==0)
break;
else
map[i][j] = weight;
}
cout<<"请输入起始点"<<endl;
cin>>origin;
//也可以通过遍历邻接矩阵找到入度为0的点找到源点
map[origin][origin]=0;
/*初始化dist[]与pre[]
*dist[]初始值为源点与其余顶点i的权值,即map[origin][i],不存在弧则为无穷大MAX
*pre[] 中,若其余顶点i与源点有弧,则pre[i]=1,否则等于0
*/
for(i=1;i<=n;i++)
{
dist[i]=map[origin][i];
if(map[origin][i] != MAX && map[origin][i] != 0)
pre[i]=origin;
}
s[origin]=1;//初始化s[],即将源点加入s中
findMin(origin);
/*输出顶点的顶点的最短路径*/
for(i=1;i<=n;i++)
{
cout<<"从起点"<<origin<<"去顶点"<<i<<"的最短路径为:";
findPath(i);
cout<<" 最短距离为:"<<dist[i];
cout<<endl;
}
return 0;
}
实现示例:
例子1:
例子2: