您的位置:首页 > 其它

Dijkstra算法

2015-10-24 15:52 363 查看
  Dijkstra算法用于求解单源最短路径问题。

  Dijkstra算法最核心的步骤在于,每次从剩余节点中选取一个节点v加入已访问节点集合的时候,我们便以v为中间节点,查看从源点出发经过v到剩余节点k和不经过v到剩余节点k哪个更短,如果经过v到剩余节点k更短的话,我们需要更新从源点到k的距离值,以及将k的前驱设置为v。

  换句话说就是,当我们从源点向目标节点走的时候,每走一步,下一步面临若干选择,当我们选择了目前的一条最短路,即选择了某个k点的时候,从源点到目标点的最短路就多了一种选择——走k和不走k。如果我们走k到剩余节点更短的话,我们当然要选择k,并且要更新这个最短路径。

 举个栗子

 


  我们需要三个数组

dist数组,记录从源点到某点的最短路径长度

path数组,记录v点最短路径的上一个节点

visit数组,记录某点有没有被访问过

 (1)开始,我们站在源点,加入是0点,我们只能看到1、2、3,所以

0123456
distinf466infinfinf
path-1-1-1-1-1-1-1
visit1-1-1-1-1-1-1
  开始时,我们选择了最小值1节点,此时剩余节点就是2、3、4、5、6。

  以1为中间节点,更新到剩余顶点的值。

0123456
distinf45611infinf
path-10101-1-1
visit1100000
  这里解释一下,我们加入了1号节点,我们站在1,下一步我们能看到2和4,所以,2和4到源点的最短路可能因为经过1这条最新的路径而改变,例如,本来从源点到2的距离为6,由于经过1,源点到2的距离dist[1]+1=5<6,所以,源点到2的最短距离我们就要更新为5,且这个距离是通过走1这个节点得到的,所以,2的最短路径的前驱就更新为1。同理,0到4本来是无穷(因为站在0点,不知道怎么才能到4),但是,当我们站在1点,到4的距离为dist[1]+7=11,小于无穷,所以,我们更新源点到4的最短距离为11,到4的最短路径要经过1,所以4的前驱设置为1

(2)在当前的dist数组中选择最小的值2,下一步就是要以2为中间节点进行观察,也就是说,我们现在站在2处。此时剩余节点是3、4、5、6。

0123456
distinf456119inf
path-101012-1
visit1110000
  同理,站在2处,我们能看到4和5,对于4,经过2到4距离为dist[2]+6=11,不更新。经过2到5,距离为dist[2]+4=9,小于无穷,更新之。

  后面的操作就是进行重复,直到所有点的visit值为1。

  

  最后我们得到的结果为

0123456
distinf45610916
path-1010524
visit1111111
  最后dist数组就记录了从源点0到每个点的最短路径长度,path数组记录了最短路径上该点的上一个节点。

  最后我们要输出最短路径,就是要不断利用path数组,借助栈进行输出。

  例如,我们要输出从0到6的最短路径,6进栈,查path表,6的前面是4,4进栈,4的前面是5,5进栈,5的前面是2,2进栈,2的前面是1,1进栈,1的前面是0,0进栈,0的前面是-1,结束,所有元素出栈就是最短路径:0->1->2->5->6,最短路径长度为16。

#include<cstdio>
#define MAXSIZE 100
#define INF 99999
int MGraph[MAXSIZE][MAXSIZE];     //图
int path[MAXSIZE];
int dist[MAXSIZE];
int visit[MAXSIZE];
void init(int n)
{
for(int i = 0; i < n; ++i)
{
path[i]=-1;
visit[i]=0;
}
}
void createG(int e)
{
int val;
int a,b;
for(int i = 0; i < e; ++i)
{
for(int j = 0; j < e; ++j)
{
MGraph[i][j] = INF;
}
}
for(int i = 0; i < e; ++i)
{
scanf("%d%d%d",&a,&b,&val);
MGraph[a][b]=val;
}
}
//获取当前从原点到剩余顶点最短路径坐标
int getlowest(int n)
{
int mm=9999;
int u;
for(int i=0; i<n; ++i)
{
if(visit[i]==0&&dist[i]<mm)
{
u=i;
mm=dist[i];
}
}
return u;
}
void dijkstra(int v0,int n)
{
for(int i=0; i<n; ++i)
{
dist[i]=MGraph[v0][i];
if(MGraph[v0][i]!=INF)
path[i]=v0;
else
dist[i]=INF;
}
visit[v0]=1;
for(int i=0;i<n;++i)
{
int u=getlowest(n);
visit[u]=1;
for(int j=0;j<n;++j)
{
if(visit[j]==0&&dist[u]+MGraph[u][j]<dist[j])
{
dist[j]=dist[u]+MGraph[u][j];
path[j]=u;
}
}
}
}
//利用栈打印最短路径,d为目标点
void printPath(int n,int d)
{
int s[MAXSIZE];
int top=0;
int c=d;
while(path[d]!=-1)
{
s[top]=path[d];
d=path[d];
++top;
}
for(int i=top-1;i>=0;--i)
{
if(i!=0)
printf("%d -> ",s[i]);
else
printf(" %d -> %d\n",s[i],c);
}
printf("最短路径长度:%d",dist[c]);
}
int main()
{
int n,e;
scanf("%d%d",&n,&e);
init(n);
createG(e);
int v0;
scanf("%d",&v0);
dijkstra(v0,n);
printPath(n,6);
return 0;
}


  算法的时间复杂度为O(n2)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: