一,概念

单源最短路径

给定一个带权有向图G=(V,E),其中每条边的权是一个实数。另外,还给定V中的一个顶点,称为源。要计算从源到其他所有各顶点的最短路径长度。这里的长度就是指路上各边权之和。这个问题通常称为单源最短路径问题。

dijkstra算法简介

迪杰斯特拉算法(Dijkstra),是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

需要注意的是,dijkstra算法只能解决正权图问题,而要解决负权图,则需要另外一种办法SPFA算法,但是SPFA算法我还不熟,本次只讲dijkstra算法

二.分析dijkstra思想

假设有这么一个图

现在我们要求1到各个顶点的最短路径

1->1间的最短路径不用想了,肯定是0

1->2之间的最短路径很明显只有一条1->2,距离为2

1->3之间,有两条路径,一条是1->3,一条是1->2->3,因为1->3之间的距离为5,而1->2->3的距离为4,所以1->3的最短路径为4

1->4之间有三条路径,分别是1->2->4, 1->4, 1->3->4,而三条路线中,最短的那条线为1->2->4,距离为3

至此所有的最短路径就都求出来了

看完是不是发现dijkstra算法的思想也不是那么难呢?原理都知道了那么我们该怎么编写代码?

三.dijkstra的编写

dijkstra的步骤如下

初始化dis[start]=0

找出一个与start点距离dis最小的未确定最短路径的点x,标记它为已经确定的点

遍历所有以x为起点的边得到(x, y, d),如果dis[y] > dis[x] + d, 则更新dis[y] = dis[x] + d

重复2,3步直到所有的点都被标记为确定最短路径的点

dijkstra算法为什么正确?

当所有的边长为非负数的时候,全局最小值不可能被被其他结点更新,所以我们在第二步中从源点出发找dis值最小的值必然是与源点的最短路径,然后在不断的选择全局最小值来拓展,得到的最短路径必然正确

我们看下面这个图

我们一开始先将源点1加入已经确定的点(红点),然后将所有相连的点标记为待处理的点(绿点),更新每个dis值

然后我们从dis值最小的结点2开始拓展,此时必然为1->2的最短路径,标记点2为红点

然后将与结点2的所有点遍历,更新对应的dis值

从与点2距离最短的4开始拓展,因为此时距离已经最小,所以标记为红点

因为点4没有出边,所以直接跳回结点2,此时只有点3为待处理的点

至此源点到所有的点的最短路径都确定了

dijkstra的堆优化

按照上面的方法直接编写的话,时间复杂度会高达O(n^2),在某些情况可能会不够,那么我们是否有O(nlogn)算法的写法呢?通过观察,这时候我们可以发现,在第2步的查找与start点距离最小的点我们可以优化。那个用什么优化呢?

这时候我们可以使用堆去优化它。

可以定义一个优先队列q,设dis值小的优先级高,这样我们可以用q.top()来通过O(logn)的时间复杂度找到dis值最小的点,而原本查找最小dis值点需要的时间复杂度为O(n)

关于存图

通常来说,在算法比赛我们通常都是用链式前向星法来储存

这里简单说一下,就不扩展了

这是关于边的信息

int head[MAXN<<1];//head[i]表示以i为头结点的边的第一条边所在的位置

struct Edge {//在边(u,v)中

int to;//to就是v

int next;//next就是下一条(u,?)的位置

int dis;//边(u,v)的长度

} e[MAXM<<1];//e[i]:第i条边的信息

这是存边的方式

void addEdge(int u,int v,int d)

{

cnt++;//第cnt条边,初始值为0

e[cnt].dis=d;//第cnt条边的权值

e[cnt].to=v;//第cnt的出边

e[cnt].next=head[u];//下一条边在e数组上的索引

head[u]=cnt;//以u为起点的边,为最后一条存进的在e数组上的索引

}

四.例题

接下来让我们照惯例的写一下模板题来练练手吧,只看不写是永远学不会的!

传送门

描述:有一个邮递员要送东西,邮局在节点 1。他总共要送 n-1 样东西,其目的地分别是节点 2 到节点 n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n-1 样东西并且最终回到邮局最少需要的时间。

输入格式

第一行包括两个整数,n 和 m,表示城市的节点数量和道路数量。

第二行到第 (m+1) 行,每行三个整数,u,v,w,表示从 u 到 v 有一条通过时间为 w 的道路。

输出格式

输出仅一行,包含一个整数,为最少需要的时间。

下面是题解

可能有的人一开始看这题目会有点蒙蔽,但其实仔细想想,送一件信我们都是从1->n,然后再从n->1返回吗?这其实不就是先求出1->n的最短路径,然后又求n->1的最短路径吗。所以只是正着来一次dijkstra,反着来一次dijkstra就行了

#include

#include

#include

using namespace std;

const int MAXN = 1000 + 5;

const int MAXM = 100000 + 5;

typedef long long LL;

struct Edge {

int to;

int next;

int dis;

} e[MAXM<<1];

int head[MAXN<<1],vis[MAXN<<1],dis[MAXN<<1];

int n,m,cnt;

void addEdge(int u,int v,int d)

{

cnt++;

e[cnt].dis=d;

e[cnt].to=v;

e[cnt].next=head[u];

head[u]=cnt;

}

//堆优化

struct node {

int dis;

int pos;

bool operator < (const node& x)const {

return x.dis < dis;

}

};

priority_queueq;

//

void dijkstra(int s)//计算1到各点的最短路径

{

memset(vis,0,sizeof(vis));

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

dis[i]=0x3fffffff;

}

dis[s]=0;

q.push({0,s});

while(!q.empty()) {

node temp = q.top();

q.pop();

int x = temp.pos, d = temp.dis;

if(vis[x])continue;

vis[x]=1;

for(int i=head[x]; i; i=e[i].next) {

int y=e[i].to;

if(dis[y]>dis[x]+e[i].dis) {

dis[y]=dis[x]+e[i].dis;

if(!vis[y]) {

q.push({dis[y],y});

}

}

}

}

}

int main()

{

cin>>n>>m;

int u,v,d;

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

scanf("%d %d %d",&u,&v,&d);

addEdge(u,v,d);//1->n

addEdge(v+n,u+n,d);//n->1 //这样不需要开两个数组(

}

LL ans = 0;

dijkstra(1);

for(int i=1;i<=n;i++)ans+=dis[i];

dijkstra(1+n);

for(int i=1+n;i<=n<<1;i++)ans+=dis[i];

printf("%lld\n",ans);

return 0;

}

最后,欢迎提意见哦!觉得有帮助的话就支持一下我吧!

JAVA编程求单源最短路径_【算法】单源最短路径——dijkstra算法相关推荐

  1. 最短路径算法(一) Dijkstra算法(贪心算法)

    Dijkstra算法是由荷兰计算机科学家狄克斯特拉(Dijkstra)于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题. 其基本原理是 ...

  2. 最短路径算法-迪杰斯特拉(Dijkstra)算法

    最短路径算法-迪杰斯特拉(Dijkstra)算法 迪杰斯特拉(Dijkstra)算法是典型最短路径算法,用于计算一个节点到其他节点的最短路径. 它的主要特点是以起始点为中心向外层层扩展(广度优先遍历思 ...

  3. 迪杰斯特拉算法求经纬度坐标的最短路径_【图的最短路径】迪杰斯特拉算法求图的最短路径...

    #include using namespace std; const int INFINITY=23678; const int M=3; /*typedef struct G { int ver[ ...

  4. java 编程求图形面积_求java编程,计算长方形面积?

    求java编程,计算长方形面积? mip版  关注:195  答案:2  悬赏:0 解决时间 2021-01-28 06:47 已解决 2021-01-27 08:26 求java编程,计算长方形面积 ...

  5. 【数据结构笔记24】单源最短路(迪克斯拉Dijkstra算法),多源最短路(弗洛伊德Floyd算法)

    本次笔记内容: 7.1.1 概述 7.1.2 无权图的单源最短路 7.1.3 有权图的单源最短路 7.1.3-s 有权图的单源最短路示例 7.1.4 多源最短路算法 文章目录 最短路径问题 最短路径问 ...

  6. java编程需要数学知识吗_初学Java编程,需要英语和数学基础吗?

    原标题:初学Java编程,需要英语和数学基础吗? "学习Java编程英语和数学是必备条件吗?"很多Java零基础学习或者转型IT行业的都会有这样的疑问,其实刚开始学习Java编程是 ...

  7. 赚多多V10自动抢单系统源码_派单连单管理新增设置订单佣金

    收到用户反馈需要连单设置时需要单独设置佣金,于是针对派单连单管理这一块做了个调整,新增了设置佣金栏目. 功能说明:派单时有设置佣金会按照设置的佣金进行计算,设置佣金为单商品价格的百分比,比如设置价格为 ...

  8. java编程东西好多记不住_课程总结

    学习java感想 这一学期的java学习过去了,Java是一门面向对象编程语言,向对象编程是Java最核心的思想,这也是区分和C等其他编程语言的一个显著特征.个人感觉java比数据结构要容易理解些,但 ...

  9. python求n的阶乘并输出身份信息_python编程求n的阶乘_使用Python编程的阶乘

    python编程求n的阶乘 Before we start implementing factorial using Python, let us first discuss what factori ...

最新文章

  1. C#2.0模拟List和内置算法
  2. java线程和操作系统线程的区别,赶紧收藏备战金三银四!
  3. 并发库应用之三 线程池与定时器应用
  4. mysql计算1000天后的日期_mysql,数据库_mysql 计算某个时间,多少天后,多少个月后时间戳,mysql,数据库,数据库设计 - phpStudy...
  5. Linux文件权限基本配置
  6. arcsde9.3 the arcsde repository is not successfully created
  7. mysql 挑战握手协议_什么是挑战握手认证协议协议,在现实中有哪些应用?
  8. pythonweb开发面试_Python web 面试题(一)
  9. 黑夜主权个人团队主页html源码
  10. javascript函数节流、防抖及使用场景
  11. 【QT】QT从零入门教程(十五):QImage和Mat的转换
  12. Win11系统如何打开地雷游戏 Win11打开扫雷游戏的教程
  13. Mysql Hash索引和B-Tree索引区别(Comparison of B-Tree and Hash Indexes)
  14. ArcMap没有工具条和菜单栏的解决方法
  15. Python实现十大经典算法动画图解
  16. oracle12c如何完全卸载_如何卸载oracle12c
  17. .Net Framework 4 如何静默安装
  18. j2ee是什么?(1)
  19. c mysql加密解密_mysql内置加密函数对数据加密
  20. 【论文阅读笔记】BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translati

热门文章

  1. Office365桌面版安装教程
  2. 通信达linux版,中标麒麟V6下wine完美运行通达信
  3. 解决部分ie 11登录不上的问题
  4. iOS---本地推送通知UILocalNotification(可以用做类似闹钟提醒)
  5. 解决Windows中d3dx9_39.dll文件丢失
  6. OSI参考模型与TCP/IP协议
  7. LCD/HDMI OUT调试经验(2)------驱动流程与基本操作
  8. 计划策略之10 (一)
  9. AvosCloud的文件存储 Demo
  10. 02- ElasticSearch(简称ES)- 文档批量操作