1.题目

分析与解题思路

dijkstra算法是典型的用来解决单源最短路径的算法,该算法采用贪心的思想,广度优先搜索的策略,每一轮从当前节点找对与其邻接的所有节点进行放松操作(比较距离源点的距离,来决定是否执行),记录当前节点为已访问,之后从所有未访问过的节点中找到距离源点最近的节点作为当前节点,重复上述操作。BFS策略体现在每次从当前节点,访问所有与其邻接的节点;贪心的思想体现在,每一轮之后,当前距离最短的点S被认为不存在从源点到S更短的路径,每次当通过S对与其邻接的节点进行放松后,可以将S从集合剔除,因为通过后续的到达S节点的距离一定更长。

证明:

假设源点为S0,当前节点为S,节点S0到节点u的距离为dis[u];

因为当前节点为S,说明其他节点u!=S,必有dis[u]>dis[S]

假如后续的节点v有一条到S的路径,源点到v的距离必然是通过S或者u进行放松的

dis[v]>=min{dis[u],dis[S]}

另外dijkstra算法只能解决权值为正的情况,当存在负权值时,算法可能出错,比如:

节点从1开始,根据贪心思想,下一下节点应该选择3,记录dis[3]=2

但是有更短的路径1->2->3 距离为1

测试用例

(测试用例1)

(测试用例2)

输入说明:

第一行:测试用例的数目

对于每一个测试用例,第一行,n,m,s;n代码节点的个数,m代表边的条数,s代码源节点

后面m行,u,v,w代表一条u->v权值为w的边

程序实现

 public List<int[]>dijkstra1(int s);使用的是课本上比较朴素的实现方法。

下面是我自己的实现方法:

//采用优先队列优化

   public List<int[]>dijkstra2(int s){

        int[]path=new int[n+1];

        int[]dis=new int[n+1];

        boolean[]mark=new boolean[n+1];

        Arrays.fill(dis, INF);

        dis[s]=0;

        path[s]=0;

        PriorityQueue pq=new PriorityQueue(n);

        for(int i=1;i<n;++i) {

            for(Node temp:table.get(s)) {

                if(!mark[temp.index]&&dis[s]+temp.weight<dis[temp.index]) {

                    if(dis[temp.index]==INF) {

                        dis[temp.index]=dis[s]+temp.weight;

                        pq.offer(temp.index, dis[temp.index]);

                    }else {

                        pq.increase(temp.index, dis[s]+temp.weight-dis[temp.index]);

                        dis[temp.index]=dis[s]+temp.weight;

                    }

                    path[temp.index]=s;

                }

            }

            mark[s]=true;

            s=pq.poll();

        }

        ArrayList<int[]>res=new ArrayList<int[]>(2);

        res.add(path);

        res.add(dis);

        return res;

    }

使用优先队列优化,每次寻找最小的距离的节点的时候就不用线性遍历整个表,可以在logV的时间复杂度内获得最小距离的节点;同时我在使用优先队列的时候,我的实现方式对优先队列有以下额外要求:(优先队列的代码有点长,具体情况源代码)

1) 能够更新元素

先找到指定的元素,根据2)中的方法,然后更新dis,如果dis变小进行上滤,dis变大进行下滤。

2) 能够在常数时间内找到在图中某个标号的节点在优先队列中的位置

一个很常见的思路就是使用空间换时间,使用一个数组保存Node在优先队列中的位置,并且在优先队列进行插入,删除,更新时也要同步更新。

运行截图

结论

朴素的实现时间复杂度是O(E*V)(我使用的是邻接表存储图),使用优先队列优化时间复杂度为O(VlogV);关于图的存储,稀疏图使用邻接表占用内存比较少,稠密图适合用邻接矩阵,访问速度很快。

dijkstra算法之优先队列优化的更多相关文章

  1. dijkstra算法与优先队列

    这是鄙人的第一篇技术博客,作为算法小菜鸟外加轻度写作障碍者,写技术博客也算是对自己的一种挑战和鞭策吧~ 言归正传,什么是dijkstra算法呢? -dijkstra算法是一种解决最短路径问题的简单有效 ...

  2. dijkstra算法的堆优化

    普通的dijkstra算法模板: //数据结构 int g[LEN][LEN]; //邻接矩阵 int vis[LEN]; //标记是否访问 int dist[LEN] //源点到各点的距离 fill ...

  3. 单源最短路径:Dijkstra算法(堆优化)

    前言:趁着对Dijkstra还有点印象,赶快写一篇笔记. 注意:本文章面向已有Dijkstra算法基础的童鞋. 简介 单源最短路径,在我的理解里就是求从一个源点(起点)到其它点的最短路径的长度. 当然 ...

  4. Dijkstra普通算法及优先队列优化

    #include<stdio.h> #include<iostream> #define maxv 100 #define inf 0x3fffffff using names ...

  5. 单源最短路-dijkstra算法(未优化)

    bool used[maxn]; int g[maxn][maxn]; // 边未联系的填充为INF int d[maxn]; void dijkstra(int s){ memset(g,false ...

  6. 【Luogu P4779】dijkstra算法的堆优化

    Luogu P4779 利用堆/优先队列快速取得权值最小的点. 在稠密图中的表现比SPFA要优秀. #include<iostream> #include<cstdio> #i ...

  7. 基于STL优先队列和邻接表的dijkstra算法

    首先说下STL优先队列的局限性,那就是只提供入队.出队.取得队首元素的值的功能,而dijkstra算法的堆优化需要能够随机访问队列中某个节点(来更新源点节点的最短距离). 看似可以用vector配合m ...

  8. POJ 3268 Silver Cow Party 最短路—dijkstra算法的优化。

    POJ 3268 Silver Cow Party Description One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbe ...

  9. Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解

    /* Dijkstra算法用优先队列来实现,实现了每一条边最多遍历一次. 要知道,我们从队列头部找到的都是到 已经"建好树"的最短距离以及该节点编号, 并由该节点去更新 树根 到其 ...

随机推荐

  1. Maven POM 模板[z]

    https://juejin.im/post/5cc826a5f265da03a33c443a [z]https://juejin.im/post/5cc826a5f265da03a33c443a S ...

  2. python之拷贝文件

    做了个小实验, 用于拷贝文件夹下面的jpg. 用于拓展, 可以引入类和方法, 拷贝你指定的任意类型的文件. import os src = 'C:\\Users\\Administrator\\Des ...

  3. 关于js函数闭包的理解

    在开始之前我们先来了解一下函数的变量作用域 JavaScript 变量可以是局部变量或全局变量. 私有变量可以用到闭包. 全局变量 函数可以访问由函数内部定义的变量,如: 实例1 function m ...

  4. LeetCode.1030-曼哈顿距离排序矩阵单元格(Matrix Cells in Distance Order)

    这是小川的第384次更新,第412篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第246题(顺位题号是1030).我们给出一个矩阵,其中R行和C列具有整数坐标(r,c)的 ...

  5. spring boot 数据源配置YAML格式

    spring: datasource: url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf- ...

  6. python 并发编程 多线程 守护线程

    做完工作这个进程就应该被销毁 单线程情况: 一个进程 ,默认有一个主线程 ,这个主线程执行完代码后 ,就应该自动销毁.然后进程也销毁. 多线程情况: 主线程代表进程结束 一个进程可以开多个线程,默认开 ...

  7. python 并发编程 多线程 Thread对象的其他属性或方法

    介绍 Thread实例对象的方法 # isAlive(): 返回线程是否活动的. # getName(): 返回线程名. # setName(): 设置线程名. threading模块提供的一些方法: ...

  8. 暴力破解-DVWA_1.9-笔记

     穷举法  通过社工尽可能的缩小密码字典的范围   所用到的工具: Firefox浏览器及其插件Proxy Switcher, OWASP ZAP代理抓包工具. OWASP ZAP  代理抓包工具 h ...

  9. HDU 4585 Shaolin (STL map)

    Shaolin Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Sub ...

  10. mysql查看锁查看

    关键词:mysql锁争用,mysql锁查看 --------------------- 作者:边城cn 来源:CSDN 原文:https://blog.csdn.net/miyatang/articl ...