Dijkstra经典算法注意点

前言

迪杰斯特拉算法,经典模板如下:

void dij(int s)
{
for(int i=1; i<=n; i++)
dis[i]=road[s][i];
vis[s]=1;
dis[s]=0; //这句话也可以不加
for(int i=1; i<n; i++)
{
int tmp=inf, k;
for(int j=1; j<=n; j++)
{
if(!vis[j] && dis[j] < tmp)
{
tmp=dis[j];
k=j;
}
}
vis[k]=1;
for(int j=1; j<=n; j++)
{
if(!vis[j] && dis[j] > dis[k]+road[k][j])
dis[j]=dis[k]+road[k][j];
}
}
}

偶然发现的问题——让我受益匪浅

迪杰斯特拉算法在最短路中的地位无可撼动,也是小白进阶过程中必学的算法之一。对于迪杰斯特拉的模板,网上可以说很多,但是笔者最近在做一道题时使用了Dijkstra算法,而且是最简单的那种,使用的代码就是上面那种,但是在输入数据时发生了错误,在评测时出现了Runtime Error(Access_Violation),我当时以为是数组发生了越界,但是看了看数据量,自己开大足够大啊,问题一点点逼近,最后调试发现一个”惊天“秘密。且看下面的代码:

const int inf=0x3f3f3f3f;
void dij(int s)
{
for(int i=1; i<=n; i++)
dis[i]=road[s][i];
vis[s]=1;
dis[s]=0; //这句话也可以不加
for(int i=1; i<n; i++)
{
int tmp=inf, k;
for(int j=1; j<=n; j++)
{
if(!vis[j] && dis[j] < tmp)
{
tmp=dis[j];
k=j;
}
}
if(tmp==inf) //如果没有更新成功,那么接下来也不会再次更新,可以结束循环了。
break;
vis[k]=1;
for(int j=1; j<=n; j++)
{
if(!vis[j] && dis[j] > dis[k]+road[k][j])
dis[j]=dis[k]+road[k][j];
}
}
}

和上面相比就多了一句话,然而我的代码却过了,为什么呢?

if(tmp==inf) //如果没有更新成功,那么接下来也不会再次更新,可以结束循环了。
break;//这句话以后就必须加上了。

原因在于,如果在第一轮寻找最小值时没有找到最小值,就是tmp的值还是inf时,如果没有这句话会怎样?需要注意的是,这时k的值还是不确定的,k的值任意,就有可能越界,而且很有能越界,导致问题,那为什么以前使用没有出现问题呢,这是因为c++开始初始化一般会初始化为零,或者因为数组开的大,k的值还在数组范围内,但是如果多次调用这个函数,而这一次调用的数据范围比上一次要小的话,这个k很有可能还是上次的值(因为编译器优化的原因),那么就有可能越界。

这段代码笔者在《啊哈!算法》和《算法竞赛入门经典》中都看到过,书中都是没有添加上面那句判断语句,只是提到了可以使用而已,发现这中情况后,这句判断语句是一定要加了。

谨以记录,前车之鉴,后事之师。

END

Dijkstra经典算法注意点的更多相关文章

  1. 经典算法题每日演练——第十七题 Dijkstra算法

    原文:经典算法题每日演练--第十七题 Dijkstra算法 或许在生活中,经常会碰到针对某一个问题,在众多的限制条件下,如何去寻找一个最优解?可能大家想到了很多诸如“线性规划”,“动态规划” 这些经典 ...

  2. 经典算法研究系列:二、Dijkstra 算法初探

    July   二零一一年一月 本文主要参考:算法导论 第二版.维基百科. 一.Dijkstra 算法的介绍 Dijkstra 算法,又叫迪科斯彻算法(Dijkstra),算法解决的是有向图中单个源点到 ...

  3. 一篇文章讲透Dijkstra最短路径算法

    Dijkstra是典型最短路径算法,计算一个起始节点到路径中其他所有节点的最短路径的算法和思想.在一些专业课程中如数据结构,图论,运筹学等都有介绍.其思想是一种基础的求最短路径的算法,通过基础思想的变 ...

  4. 算法很美,听我讲完这些Java经典算法包你爱上她

    大家好,我是小羽. 对于编程来说的话,只有掌握了算法才是了解了编程的灵魂,算法对于新手来说的话,属实有点难度,但是以后想有更好的发展,得到更好的进阶的话,对算法进行系统的学习是重中之重的. 对于 Ja ...

  5. Java中的经典算法之冒泡排序(Bubble Sort)

    Java中的经典算法之冒泡排序(Bubble Sort) 神话丿小王子的博客主页 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一 ...

  6. 迪杰斯特拉(dijkstra)算法的简要理解和c语言实现(源码)

    迪杰斯特拉(dijkstra)算法:求最短路径的算法,数据结构课程中学习的内容. 1 . 理解 算法思想::设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合 ...

  7. Atitit 图像处理30大经典算法attilax总结

    Atitit 图像处理30大经典算法attilax总结 1. 识别模糊图片算法2 2. 相似度识别算法(ahash,phash,dhash)2 3. 分辨率太小图片2 4. 横条薯条广告2 5. 图像 ...

  8. Java中的经典算法之选择排序(SelectionSort)

    Java中的经典算法之选择排序(SelectionSort) 神话丿小王子的博客主页 a) 原理:每一趟从待排序的记录中选出最小的元素,顺序放在已排好序的序列最后,直到全部记录排序完毕.也就是:每一趟 ...

  9. 最短路径之迪杰斯特拉(Dijkstra)算法

    迪杰斯特拉(Dijkstra)算法主要是针对没有负值的有向图,求解其中的单一起点到其他顶点的最短路径算法.本文主要总结迪杰斯特拉(Dijkstra)算法的原理和算法流程,最后通过程序实现在一个带权值的 ...

随机推荐

  1. Python(3) 进制转换

    2进制 :0b8进制: 0o16进制: 0x10进制:原来的数据 进制转换:bin() 方法:转化为 2进制 >>> bin(10)'0b1010'oct() 方法:转化为 8进制& ...

  2. js去重的es6做法和es5做法

    1.es5做法var array=[1,3,4,5,2,3,4,5,5,5];var ob={};var result=[];array.forEach(function (a) { var key= ...

  3. JavaScript自增和自减

    一.自增++ 通过自增运算符可以使变量在自身的基础上加一: 对于一个变量自增以后,原变量的值会立即自增一: 自增符号:++ 自增分为两种:1.后++(a++):2.前++(++a): 共同点:a++ ...

  4. JDK7的新特性

    本篇博客的内容 一.二进制字面量 二.数字字面量可以出现下划线 三.switch 语句可以用字符串 四.泛型简化 五.异常的多个catch合并 六.try-with-resources 语句 一.二进 ...

  5. BZOJ 3357: [Usaco2004]等差数列 动态规划

    Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...

  6. 浙大PAT CCCC L3-013 非常弹的球 ( 高中物理题 )

    题目链接 题意 : 刚上高一的森森为了学好物理,买了一个“非常弹”的球.虽然说是非常弹的球,其实也就是一般的弹力球而已.森森玩了一会儿弹力球后突然想到,假如他在地上用力弹球,球最远能弹到多远去呢?他不 ...

  7. 【Java】JavaMail使用网易企业邮箱发邮件

    邮件发送器 /** * 邮件发送器 * * @author Zebe */ public class MailSender implements Runnable { /** * 收件人 */ pri ...

  8. PHP导出excel文件名中文IE乱码解决

    <?php $ua = strtolower($_SERVER['HTTP_USER_AGENT']); if(preg_match('/msie/', $ua) || preg_match(' ...

  9. IIS新建项目

    我在写网站的时候要 经常帮公司的游戏写界面,他们用的都是VS,然后要用IIS创建项目(配置环境)然后页面才能够在浏览器上看效果. 那就要先了解啥是IIS: IIS是Internet Informati ...

  10. Codeforces Round #587 (Div. 3) F. Wi-Fi(单调队列优化DP)

    题目:https://codeforces.com/contest/1216/problem/F 题意:一排有n个位置,我要让所有点都能联网,我有两种方式联网,第一种,我直接让当前点联网,花费为i,第 ...