算法导论 25.3 Johnson算法

算法导论 25.3 Johnson算法一 Johnson 算法的思想 nbsp nbsp nbsp nbsp nbsp nbsp 如果图 G 中所有的边权重均为非负值 通过对每个结点进行一次 Dijkstra 算法来找到所有结点对之间的最短路径 如果图 G 中有负值的边但没有权重为负值的环路 就计算出一组新的非负权重值 并按同样的方法计算 二 新权重的确定 nbsp nbsp nbsp nbsp nbsp nbsp 我们定义新权重 w u v w u v h u h v 满足两个性质 一是对于所有结点对 u v 路径 p 是使用原权

一,Johnson算法的思想

二,新权重的确定

        我们定义新权重w'(u,v)=w(u,v)+h(u)-h(v),满足两个性质:一是对于所有结点对(u,v),路径p是使用原权重函数w时从结点u到v的一条最短路径,当且仅当p是在使用新权重函数w’时从u到v的一条最短路径,二是新权重为非负值。

三,Johnson算法介绍

四,Johnson算法的伪代码

JOHNSON(G,w)

1. compute G’,where G’.V=G.V∪{s},G’.E=G.E∪{(s,v):v∈G.V},w(s,v)=0 for all v∈G.V

2. if BELLMAN_FORD(G’,w,s)==FALSE

3.     print”the input graph contains a negative-weight cycle”

4. else for each vertex v∈G’.V

5.             set h(v) to the value of δ(s,v) computed by the Bellman-Ford algorithm

6.         for each edge(u,v)∈G’.E

7.             w'(u,v)=w(u,v)+h(u)-h(v)

8.             let D=(duv)be a new n*n matrix

9.             for each vertex u∈G.V

10.                run DIJKSTRA(G,w’,u) to compute δ'(u,v) for all v∈G.V

11.                for each vertex v∈G.V

12.                    duv=δ'(u,v)+h(v)-h(u)

13. return D

第1行中,在图G中加入结点S,并让S到各结点的权重为0;第2行中,用Bellman-Ford算法计算S到各结点的最短路径,如果返回false,说明有负环,如果为true,继续下面的语句;第4-12行中,有四个循环,第一个循环将每个结点的h值算出,也就是前面BF算法算出来的最短路径,第二个循环将每条边的权重根据新权重确定方法重新赋值,随后创建最终的最短路径权重矩阵D,第三个循环对每个结点进行一次Dijkstra算法计算每个结点到其他所有结点的最短路径,并让duv等于算出来的最短路径减去前面加上的h(u)-h(v);第13行返回最短路径权重矩阵D

五,Johnson算法的复杂度

时间复杂度:O(V²lgV+VE)

六,Johnson算法的代码

这里用了二维数组表示矩阵

int Johnson_Algo(Graph * graph) { int D; D = (int )malloc(NODESIZE * sizeof(int *)); for (int i = 0; i < NODESIZE; i++) { D[i] = (int *)malloc(NODESIZE * sizeof(int)); } Graph *g = buildGraph_Johnson(graph); if (Bellman_Ford_Algo(g, g->getNodeList().back()) == false) { cout << "存在负边环"; } else { for (int i = 0; i < g->getNodeList().size()-1; i++) { g->getNodeList()[i]->setH(g->getNodeList()[i]->getD()); } for (int j = 0; j < g->getEdgeList().size(); j++) { Edge *edge = g->getEdgeList()[j]; edge->setW(edge->getW() + edge->getStartNode()->getH() - edge->getEndNode()->getH()); } for (int u = 0; u < graph->getNodeList().size(); u++) { Dijkstra_Algo(graph, graph->getNodeList()[u]); for (int v = 0; v < graph->getNodeList().size(); v++) { D[u][v] = graph->getNodeList()[v]->getD()+ graph->getNodeList()[v]->getH()- graph->getNodeList()[u]->getH(); } } } return D; }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/216122.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午12:30
下一篇 2026年3月18日 下午12:30


相关推荐

  • oracle创建表空间出错的原因和解决办法「建议收藏」

    oracle创建表空间出错的原因和解决办法「建议收藏」相信很多人在创建表空间的时候遇到过这样问题.问题原因:这是因为oracle数据库是在虚拟机或者是服务器上安装的.你在本地创建文件的时候自然会找不到文件夹.就会造成图上的错误解决办法:1.打开虚拟机2.连接上oracle数据库3.找到安装oracle文件夹的位置例如:D:\oracle11g\app\oracle\oradata\4.在cmd上敲命令:createtablespacetudoudatafile‘D:\oracle11g\app\oracle\orad…

    2022年7月11日
    22
  • 关于高通平台9008线刷的一些注意点,供小白食用。

    关于高通平台9008线刷的一些注意点,供小白食用。这是我第一次写博文 所以有很多地方还需要改进 废话不多说 我们直接上干货 高通 QPST 线刷其实就是利用高通芯片自带的 9008 端口 将手机系统内的所有分区的镜像文件 直接刷写手机 这个刷机方式比 REC 卡刷和 fastboot 线刷 更底层 高效 强大 这种方式 不需要进入手机的任何分区 就可以直接刷写手机固件 REC 卡刷必须要手机能进入 recovery 模式 并且要是第三方

    2026年3月26日
    1
  • 单片机ds1302时钟程序(51单片机液晶显示程序)

    /*总体要求*//*在1602上显示年月日星期时分秒,并且按照秒来实时更新显示可以闹钟设定,到点报警功能,报警响起时,任意键可以取消报警四个按键,根据功能可以调节参数,分别为功能键,数值增大键,数值减少键,闹钟查看键,每次按键按下,蜂鸣器都会滴一声,利用DS12C887实现断电后,再次上电,时间仍可以准确显示*//*另外这个程序中文部分是学习了一个半月C语…

    2022年4月14日
    207
  • vue集成capacitor

    vue集成capacitor1 在项目本地安装 capacitor cli 和 capacitor corenpminsta capacitor cli capacitor core2 初始化 capacitor 项目 npxcapinit 说明 webDir 选择 dist 文件夹 因为之后打包后的文件夹默认为 dist2 安装 capacitor androidnpmin capacitor android3 打包静态资源 npmrunbuild4 添加 android 平台 npxcapad

    2026年2月14日
    3
  • SQLServer中使用SUBSTRING截取字符串[通俗易懂]

    SQLServer中使用SUBSTRING截取字符串[通俗易懂]SUBSTRING返回字符、binary、text     或     image     表达式的一部分。有关可与该函数一起使用的有效     Microsoft®     SQL     Server™     数据类型的更多信息,请参见数据类型。  语法SUBSTRING     (     expression     ,     start     ,     length     )  参数expression是字符串、二进制字符串、text、image、列或包

    2022年5月23日
    141
  • java 标识符命名规则_Java标识符命名规则

    java 标识符命名规则_Java标识符命名规则Java 标识符命名规则 Java 语言的命名规范需遵守下面 9 个条件 1 标识符由 26 个英文字符大小写 a zA Z 数字 0 9 下划线 和美元符号 组成 2 不能以数字开头 不能是关键字 3 严格区分大小写 4 标识符的可以为任意长度 5 包名多个单词组成时所有字母小写 例 packagecom csdn 6 类名和接口多个单词组成时所有单词的首字母大写 例 HelloWorld 7 变

    2026年3月26日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号