三种最短路的总结

三种最短路的总结

 

三种最短路算法的对比
  floyd   dijkstra  Bellman-ford
空间复杂度 o(N^2) 0(M) 0(M)
时间吗复杂度  O(N3)     O((M+N)logN)    O(MN)
适用情况 稠密图 稠密图 稀疏图
负权边 不可以 不可以 可以

floyd算法简单,dijkstra不能解决负权边优化后可以得到MLogN的复杂度,bellman可以解决负权边。

下面再介绍一下贝尔曼、福特算法的优化

给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。 我们约定有向加权图G不存在负权回路,即最短路径一定存在。当然,我们可以在执行该算法前做一次拓扑排序,以判断是否存在负权回路,但这不是我们讨论的重点。

算法思想:我们用数组d记录每个结点的最短路径估计值,用邻接表来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止

期望的时间复杂度O(k e), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。

实现方法:

 建立一个队列,初始时队列里只有起始点,再建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点作为起始点去刷新到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空。

判断有无负环:
  如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)

暂时先给出代码,具体我也没理解清楚;

#include<stdio.h>
#include<string.h>
#include<queue>
#define N 210
#define M 2010
#define INF 0x3f3f3f3f//定义无穷大 
using namespace std;
int dis[N],vis[N],head[N],n,m,edgenum;
struct node{
	int from,to,cost,next;
}edge[M];
void init(){
	edgenum=0;
	memset(head,-1,sizeof(head));
}
void add(int u,int v,int w){
	node E={u,v,w,head[u]};
	edge[edgenum]=E;
	head[u]=edgenum++;
}
void spfa(int beg,int end){//SPFA算法核心 
	queue<int>q;
	q.push(beg);//将起点加入队列 
	memset(vis,0,sizeof(vis));//用来标记是否在队列中 
	memset(dis,INF,sizeof(dis));
	vis[beg]=1;
	dis[beg]=0;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		int i;
		for(i=head[u];i!=-1;i=edge[i].next){//遍历起点为U的所有的边。 
			int v=edge[i].to;
			if(dis[v]>dis[u]+edge[i].cost){//更新点的最短路 
				dis[v]=dis[u]+edge[i].cost;
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	if(dis[end]==INF)
		printf("-1\n");
	else
		printf("%d\n",dis[end]);
}
int main(){
	while(scanf("%d%d",&n,&m)!=EOF&&n!=0&&m!=0){
		init();//需要初始化邻接表的表头。 
		while(m--){
			int a,b,cost;
			scanf("%d%d%d",&a,&b,&cost);
			add(a,b,cost);//对图进行输入,由于是无向图,所以正反两次输入,不用判断重边。 
			add(b,a,cost);
		}
		int beg,end;
		scanf("%d%d",&beg,&end);
		spfa(beg,end);
	}
	return 0;
}

 
 

 

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

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

(0)
上一篇 2021年9月28日 上午9:00
下一篇 2021年9月28日 上午10:00


相关推荐

  • 5G NGC — CHF 融合计费

    5G NGC — CHF 融合计费目录文章目录目录话单 CDR 离线计费和在线计费融合计费融合计费业务流程图话单 CDR 通信专业术语里面的话单 和我们平常所指的话单 是两个不同的概念 我们平常所指的话单 例如通过运营商 App 查到的那些账单和详单 账单 是月度总费用的明细 详单 是每天通话或上网的具体记录 简单来说 账单是详单的汇总结算 通信行业专业术语里所说的话单 我们称之为 CDR CallDetailRe 呼叫详细记录 CDR 是通信系统内部传递的一种文件数据 记录了每一条原始通信记录的信息

    2026年3月20日
    3
  • k8s 资源管理_k8s扩容命令

    k8s 资源管理_k8s扩容命令k8s管理器介绍yaml资源管理器介绍管理器介绍在Kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理Kubernetes。Kubernetes的本质就是一个集群系统,用户可以在集群中部署各种服务。所谓的部署服务,其实就是在Kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。Kubernetes的最小管理单元是Pod而不是容器,所以只能将容器放在Pod中,而Kubernetes一般也不会直接管理Pod,而是通过Pod控制器来管理Pod的。Pod提供服务之后

    2022年8月11日
    6
  • latex中的希腊字母表_LaTeX怎么念

    latex中的希腊字母表_LaTeX怎么念希腊字母,我们从小学开始认识它,但对它的读音我依旧靠蒙(说蒙真的感觉好羞愧啊)。尤其在大学数学分析中,希腊字母超级多,很多经典的公式,都由希腊字母来表示。它自然成为数学领域不可或缺的符号,将数学复杂的内容变为了清晰易懂的,平易近人。今天,为什么要谈希腊字母呢?还得从前天我写LaTeX时用ε\varepsilon说起,在百度百科查到的是ϵ\epsilon,,符号不是我要的,顿时对百度的憎恶感突增好几倍

    2022年10月13日
    4
  • 控制中的各种函数MATLAB仿真

    控制中的各种函数MATLAB仿真控制系统的MATLAB仿真1MATLAB简介MATLAB是Mathworks公司开发的一种集数值计算、符号计算和图形可视化三大基本功能于一体的功能强大、操作简单的优秀工程计算应用软件。MATLAB不仅可以处理代数问题和数值分析问题,而且还具有强大的图形处理及仿真模拟等功能。从而能够很好的帮助工程师及科学家解决实际的技术问题。MATLAB的含义是矩阵实验室(MatrixL

    2022年6月4日
    63
  • 分页的sql语句_自动分页

    分页的sql语句_自动分页下文将为您介绍三种SQL分页语句写法,如果您也遇到过类似的问题,不妨一看,相信对您会有所启迪。SQL分页操作是经常会遇到的,下面就将为您介绍三种SQL分页语句,供您参考,希望对您学习SQL分页能够有所帮助。方法一(适用于SQLServer2000/2005)SELECTTOP页大小* FROMtable1 WHEREidNOTIN

    2022年8月30日
    6
  • Qwen2大模型微调入门实战(附完整代码)超详细讲解

    Qwen2大模型微调入门实战(附完整代码)超详细讲解

    2026年3月13日
    4

发表回复

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

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