Dijkstra算法1:邻接矩阵表示

从某个源点到其余各顶点的最短路径问题:

Dijkstra算法解决了有向图G=(V,E)上带权的单源最短路径问题,但是要求所有边的权值非负(原因后面叙述)。

Dijkstra算法思想为:设 G = (V, E) 是一个带权有向图,把图中顶点集合 V 分成两组,第一组为以求出最短路径顶点的集合(用S表

,初始时 S 中只有一个源点,以后每求得一条最短路径 , 就将其加入到集合 S 中,直到全部顶点都加入到 S 中,算法就结束了)

,第二组为其余未确定最短路径的顶点的集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入 S 中。在加入的过

程中,总保持从源点 v 到 S 中各顶点的最短路径长度不大于从源点 v 到 U 中任何顶点的最短路径长度。此外,每个顶点对应一个距

离,S 中的顶点的距离就是从 v 到此顶点的最短路径长,U中的顶点的距离,是从 v 到此顶点只包括 S 中的顶点为中间顶点的当前最短

路径长度。伪代码:

DIJKSTRA(G, w, s)
1  INITIALIZE-SINGLE-SOURCE(G, s)//初始源
2  S ← Ø
3  Q ← V[G]
4  while Q ≠ Ø
5      do u ← EXTRACT-MIN(Q)//找出Q中距离最短路径
6         S ← S ∪{u}
7         for each vertex v ∈ Adj[u]
8             do RELAX(u, v, w)//松弛操作

单源最短路径算法中使用了松弛(relaxation)操作。对于每个顶点v∈V,都设置一个属性d[v],用来描述从源点s到v的最短路径上权值的上界,称为最短路径估计(shortest-path estimate)。π[v]代表S到v的当前最短路径中v点之前的一个点的编号。一次松弛操作可以减小最短路径估计的值d[v]。

每个单源最短路径算法中都会调用INITIALIZE-SINGLE-SOURCE,然后重复对边进行松弛的过程。另外,松弛是改变最短路径和前趋的唯一方式。下面的伪代码对边(u,v)进行了一步松弛操作。

RELAX(u, v, w)
  if(d[v]>d[u]+w(u,v))
  then d[v]←d[u]+w(u,v)     
  π[v]←u

程序实例:

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1&lt;=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

输出:

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

示例:

2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0

#include<cstdio>
#include <climits>
#include <iostream>
using namespace std;
const int inf = INT_MAX>>1;
const int NV = 101;
int dis[NV];
int map1[NV][NV];
bool mark[NV];
int m,n;
void dijkstra(int src)
{
    int i, k, j,minf;
for( i = 0; i < n; ++i)
{
    mark[i] = false;
    dis[i] = map1[src][i];
}
dis[src] = 0;
mark[src] = true;
for( i = 1; i < n; ++i)
{
minf = inf;
k = src;
for(j = 0; j < n; ++j)
{
    if(dis[j] < minf && (!mark[j]))
    {
        minf = dis[j];
        k = j;
    }
}
mark[k] = true;
for(j = 0; j < n; j++)
{
    int temp = dis[k] + map1[k][j];
    if(!mark[j] && temp < dis[j])
        dis[j] = temp;
}
}
 return;
}
int main()
{
    while(scanf(“%d %d”,&n,&m), m || n)
    {
      for(int i = 0; i < n; ++i)
      {
          map1[i][i] = inf;
      for(int j = i + 1; j < n; j++)
      {
          map1[i][j] = inf;
          map1[j][i] = inf;
      }
      }
while(m–)
{
int v1,v2,t;
scanf(“%d %d %d”, &v1, &v2, &t);
if(map1[v1 – 1][v2 – 1] > t)
{
map1[v1 – 1][v2 – 1] = t;
map1[v2 – 1][v1 – 1] = t;
}
}
 dijkstra(0);
 printf(“%d”,dis[n – 1]);
    }
    return 0;
}

对于迪杰斯特拉算法
所有边的权值非负是因为  Dijkstra由于是贪心的,每次都找一个距源点最近的点(dmin),然后将该距离定为这个点到源点的最短路径(d[i] ← dmin);但如果存在负权边,那就有可能先通过并不是距源点最近的一个次优点(dmin’),再通过这个负权边 L (L < 0),使得路径之和更小(dmin’ + L < dmin),则 dmin’ + L 成为最短路径,并不是dmin,这样Dijkstra就被囧掉了。

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/haida_liudan/article/details/8811145
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞