初级算法-Dijkstra算法

问题描述

一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”。
例如求下图中的1号顶点到2、3、4、5、6号顶点的最短路径。


问题解释

  • 使用二维数组e来存储顶点之间边的关系


  • 一维数组dis来存储1号顶点到其余各个顶点的初始路程



    dis数组中的值称为最短路的“估计值”。

  • 1到2号通过dis可知为最短。再看2号有什么出边。
    2>3 or 2>4 , 2到3能否让1到3的路程变短?

  • 比较dis[3]和dis[2]+e[2][3]的大小
    dis[3] = 1到3
    dis[2]+e[2][3] 1到2 再通过2-3到3号
    dis[2] = 1到2
    e[2][3]= 2->3

  • dis[3]=12,
    dis[2]+e[2][3]=1+9=10,
    dis[3]>dis[2]+e[2][3],
    更新
    dis[3]为10

-专业术语叫做“松弛”
1-3为dis[3],通过2->3这条边松弛成功。

-同理
通过2->4(e[2][4])
将dis[4]的值从∞松弛为4
dis[4] = ∞,dis[2] + e[2][4] = 1 + 3 = 4
dis[4] > dis[2] + e[2][4]
so更新dis[4]为4


image.png

Dijkstra算法的主要思想:通过“边”来松弛1号顶点到其余各个顶点的路程。

  • 因此得出可以通过松弛的方法计算dis数组!

  • 最终结果


    image.png

    -总结
    基本思想:找到最近顶点,进行扩展,得出最近顶点的最短路径。

解题思路

  • 顶点可分为两类
    已知最短路程的顶点集合P
    未知最短路径的顶点集合Q

已知最短路径的顶点集合P中只有源点一个顶点 1
book[ i ]数组记录那些在P中

book[ i ]=1 表示 i在P中
book[ i ]=0表示i在Q中

  • 源点
    源点s到自己的最短路径为0
    即dis=0

源点有能直接到达的顶点i
dis[ i ]设为e[s][ i ]

  • 集合Q的所有顶点中选择一个离源点s最近的顶点u(即dis[u]最小)
    加入到集合P
    考察所有以点u为起点的边,对每一条边进行松弛操作。
    可将u-v添加到s-v的路径
    dis[u]+e[u][v]
    比目前已知的dis[v]的值要小,则替代dis[v]

-重复第3步,如果集合Q为空,算法结束

解法

-代码

#include <stdio.h>
int main()
{
    int e[10][10],dis[10],book[10],i,j,n,m,t1,t2,t3,u,v,min;
    int inf=99999999; //用inf(infinity的缩写)存储一个我们认为的正无穷值
    //读入n和m,n表示顶点个数,m表示边的条数
    scanf("%d %d",&n,&m);
                                                           
    //初始化
    for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
            if(i==j) e[i][j]=0;
              else e[i][j]=inf;
                                                                     
    //读入边
    for(i=1;i<=m;i++)
    {
        scanf("%d %d %d",&t1,&t2,&t3);
        e[t1][t2]=t3;
    }
    //初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
    for(i=1;i<=n;i++)
        dis[i]=e[1][i];
    //book数组初始化
    for(i=1;i<=n;i++)
        book[i]=0;
    book[1]=1;
                                                           
    //Dijkstra算法核心语句
    for(i=1;i<=n-1;i++)
    {
        //找到离1号顶点最近的顶点
        min=inf;
        for(j=1;j<=n;j++)
        {
            if(book[j]==0 && dis[j]<min)
            {
                min=dis[j];
                u=j;
            }
        }
        book[u]=1;
        for(v=1;v<=n;v++)
        {
            if(e[u][v]<inf)
            {
                if(dis[v]>dis[u]+e[u][v])
                    dis[v]=dis[u]+e[u][v];
            }
        }
    }
                                                           
    //输出最终的结果
    for(i=1;i<=n;i++)
        printf("%d ",dis[i]);
                                                               
    getchar();
    getchar();
    return 0;
}

时间复杂度

O(N2N)

每次找到离1号顶点最近的顶点的时间复杂度是O(N)

可以用“堆”来优化,时间复杂度降低到O(logN)。

对于边数M少于N2的稀疏图来说
可以用邻接表来代替t 邻接矩阵,复杂度优化到O(MlogN)

优化

https://blog.csdn.net/ahalei/article/details/23356781
另外一种存储图的方法:邻接表,这样空间和时间复杂度就都是M。对于稀疏图来说,M要远远小于N2。先上数据,如下。

image.png

第一行两个整数n m。
n表示顶点个数(顶点编号为1~n),
m表示边的条数。
接下来m行表示,
每行有3个数x y z,表示顶点x到顶点y的边的权值为z。下图就是一种使用链表来实现邻接表的方法。

image.png

每个顶点都建立了一个单链表
可以通过遍历
得出每个的点边

  • 解法
    为每一条边编号!1-m,1,4,9
    u、v和w三个数组用来记录每条边的具体信息,即u[i]、v[i]和w[i]表示第i条边是从第u[i]号顶点到v[i]号顶点,且权值为w[i]。
image.png

first数组来存储每个顶点其中一条边的编号
假如1号顶点有边1 4 9, 将first[1]设为1,顶点i没有以1 4 9则设为-1


image.png

下标为一,第一条边 14 9,
u[i]为起始点的第一条边,就将next[i]的值设为-1


image.png

下标2 读入4 3 8
4号顶点为起始点的第一条边,所以将next[2]的值设为-1。


image.png
 读入第3条边(1 2 5)

起点为1,但是1条已经是1开头了,所以讲next设为1


image.png

读入第四条边246 2号顶点为起始点的第一条边,所以将next[4]的值设为-1。


image.png
    读入第5条边(1 3 7)

这条边的编号为5,起始顶点又是1号顶点。此时需要将first[1]的值设为5,并将next[5]的值改为3。


image.png

读入第5条边(1 3 7),将
将first[1]的值设为5,并将next[5]的值改为3。


image.png

遍历1号顶点


image.png
int n,m,i;
//u、v和w的数组大小要根据实际情况来设置,要比m的最大值要大1
int u[6],v[6],w[6];
//first和next的数组大小要根据实际情况来设置,要比n的最大值要大1
int first[5],next[5];
scanf("%d %d",&n,&m);

/初始化first数组下标1~n的值为-1,表示1~n顶点暂时都没有边
for(i=1;i<=n;i++)
    first[i]=-1;

for(i=1;i<=m;i++)
{
   scanf("%d %d %d",&u[i],&v[i],&w[i]);//读入每一条边
  next[i] = first[u[i]];
  first[u[i]]= i;

遍历1号顶点所有边的代码如下。

k = first[1]; //
while (k!-1_ 
{
  printf("%d %d %d \n", u[k], v[k], w[k]);
  k  = next[k];

遍历每个顶点的所有边的代码如下。

for(i=1;i<=n;i++)
{
    k=first[i];
    while(k!=-1)
    {
        printf("%d %d %d\n",u[k],v[k],w[k]);
        k=next[k];
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 校园导航这个课题,分别可以使用了Dijkstra(迪杰斯特拉)算法,Floyd(弗洛伊德)算法和Bellman-F...
    锋芒工作室阅读 657评论 0 0
  • 1.Dijkstra算法介绍 算法特点: 迪科斯彻算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题...
    Plato718阅读 2,645评论 0 0
  • 一、定义 在一幅加权有向图中,最短路径是指从顶点s到顶点t的最短路径是所有从s到t的路径中的权重最小者。求解最短路...
    null12阅读 2,436评论 0 4
  • 八、照片 “亲爱的黛艾瑞:酒吧的墙上贴满的照片。 我细细看着照片上的人,他们笑着,笑得如此美好,嘴角洋溢着...
    牧狼诗人阅读 241评论 3 4
  • 孩子的作业图1昨天,图2今天!孩子的潜力是有多大啊!我很庆幸发现孩子问题没有指责,抱怨,打击孩子!因为我知道这样的...
    玮_5fea阅读 355评论 0 2