首页 > 其他分享 >最短路

最短路

时间:2024-10-31 17:08:37浏览次数:2  
标签:松弛 int 短路 负环 vis dis

Floyd算法

BFS求01最短路

题目链接

对于边权只有0和1的图,可以用BFS+deque求最短路

具体做法:前端队列存由0边更新的点,后端存由1更新的点,每次松弛从前端取

比较好想,由于是BFS,可以认为本层转移下,0边转移的点dis都相等,1边转移的点dis都相等(不一定正确),那么从前面取出来的点通过0边松弛了另一个点,dis值完全一样,放进队头也不会影响单调性,而1边松弛的点dis值+1又和后面的值一样,所以大致正确

本质上是dijkstra的特化版本

dijkstra算法

运用贪心策略,在未访问点集中选取距已访问点集最近的点,由此点拓展,堆优化后时间复杂度为\(O((n+m)logm)\)

void dijkstra() {
	for(int i=1;i<=n;i++) dis[i]=INF;
	dis[s]=0;
	q.push(make_pair(0,s));
	while(!q.empty()) {
		int x=q.top().second;
		q.pop();
		if(vis[x]) continue;	//这里注意不要重复访问,不然会TLE
		vis[x]=1;
		bfs(x) {
			int v=e[i].to;
			if(dis[v]>dis[x]+e[i].dis) {
				dis[v]=dis[x]+e[i].dis;
				if(!vis[v]) q.push(make_pair(dis[v],v));
			}
		}
	}
}

最短路DAG

固定源点的所有点最短路的集合是DAG(易证)

利用该性质可以使用一些高效算法(拓扑,DP等)

注意:对于\(v\)点的第一次更新(\(dis[v]:\ INF\ -> dis[x]+e[i].dis\))并不能保证\(dis[v]\)是\(v\)的最短路长;优先队列维护的是已完成更新的点集,因此取出的是\(dis[x]\)最小的点,并不能保证\(dis[x]+e[i].dis\)最小

因此应在dijkstra外建DAG

求路径,路径数

由于dijkstra算法是由源点向外拓展的,路径更新有连续性且形象易分析,所以常用于最短路计数

松弛的时候统计就好了

求次短路

Bellman-Ford算法

跑n次松弛操作,每次都把全部m条边松弛,由于最短路不会重复经过点,因此n次松弛后一定能找到最短路

for(int i=0; i<n; i++)
  for(int j=0; j<m; j++)
  {
  	 if(dist[a]+w<dist[b])
  	   dist[b] = dist[a] + w; //w是a->b的权重 
  }

判负环

由上文,我们进行第n+1次操作,如果还能松弛,说明走了重复点,即出现负环

加个flag看是否松弛即可

SPFA算法

基础

队列优化的Bellman-Ford,用队列存储点,找到可以松弛的边再把它连的点加进来。时间复杂度\(O(km)\),遇到网格图会退化成\(O(nm)\)。

bool SPFA() {
	for(int i=1;i<=n;i++) vis[i]=0,dis[i]=INF;
	queue<int> q;
	q.push(1)
	while(!q.empty()) {
		int x=q.front();
		q.pop();
		vis[x]=0;
		bfs(x) {
			int v=e[i].to;
			if(dis[v]>dis[x]+e[i].dis) {
				dis[v]=dis[x]+e[i].dis;
				if(!vis[v]) {
					q.push(v);
					vis[v]=1;
				}
			}
		}
	}
	return 0;
}

p.s.此份代码默认无负环,往往使用SPFA都是用于判负环。

注意加判是否入队,否则会重复操作

优化

1、DFS优化

广搜改深搜

2、SLF优化

3、LLL优化

判负环

1、边做最短路边判负环

一个点最多只能被n-1个点松弛入队,若入队次数>=n,则有重复经过,即找到负环。

在做最短路时加个cnt[]存入队次数即可。时间复杂度\(O(nm)\)。

bool SPFA() {
	for(int i=1;i<=n;i++) dis[i]=1e9;
	deque<int> q;		//SLF优化
	q.push_front(0);
	vis[0]=1;
	while(!q.empty()) {
		int x=q.front();
		q.pop_front();
		vis[x]=0;
		for(int i=head[x];i;i=e[i].next) {
			if(dis[e[i].to]>dis[x]+e[i].dis) {
				dis[e[i].to]=dis[x]+e[i].dis;
				cnt[e[i].to]++;
				if(cnt[e[i].to]>n) return 1;	//找到负环
				if(!vis[e[i].to]) {
					if(!q.empty()&&dis[e[i].to]<dis[q.front()]) q.push_front(e[i].to);
					else q.push_back(e[i].to);
					vis[e[i].to]=1;
				}
			}
		}
	}
	return 0;
}

2、只判负环

又看不懂了……

【模板】负环 里dfs SPFA被卡了(link

学长说用bfs版就ok(有朝一日我会来弄清楚这个问题的!)

与第一种判负环方法不同的是——BFS改DFS,初始化dis[]为0,再从每个点跑SPFA,每次跑不需要初始化dis[]。

1、初始化dis[]为0时,SPFA会且仅会进入负权子路径并松弛dis[]为负数,而负环也是负权子路径的一种,因此负环肯定能走到

由于是从每个点都跑,不会被某些正权边卡

当然,初始化dis[]为0注定了它不能跑最短路

2、每次跑不需要初始化dis[]是因为如果\(dis[v]>dis[x]+e[i].dis\),那么松弛可能会使后面dis值更小,更有可能找到负环;相反,如果\(dis[v] \le dis[x]+e[i].dis\),比现在搜出的dis[]还小的路径早就搜过了,那就完全没有进去搜的必要了

如果每次跑都清dis[],那就会导致上面说的“没有搜的必要”的情况进去搜了,做无用功

最坏时间复杂度是\(O(nm)\),但是往往达不到

bool SPFA(int x) {
	vis[x]=1;
	bfs(x) {
		int v=e[i].to;
		if(dis[v]>dis[x]+e[i].dis) {
			dis[v]=dis[x]+e[i].dis;
			if(vis[v]||SPFA(v)) return 1; 
		}
	}
	vis[x]=0;
	return 0;
}
bool Check() {
	for(int i=1;i<=n;i++) vis[i]=0,dis[i]=0;
	for(int i=1;i<=n;i++) if(SPFA(i)) return 1;
	return 0;
}

Johnson算法

标签:松弛,int,短路,负环,vis,dis
From: https://www.cnblogs.com/zhone-lb/p/18518398

相关文章

  • 《 C++ 修炼全景指南:十七 》彻底攻克图论!轻松解锁最短路径、生成树与高效图算法
    摘要1、引言1.1、什么是图?图(Graph)是计算机科学和离散数学中一种重要的数据结构,用来表示一组对象之间的关系。一个图由顶点(也称为节点,Vertex)和边(Edge)组成。顶点表示实体,而边则表示实体之间的关联或连接关系。根据边的性质,图可以分为无向图和有向图。在无向图中,边没有方向......
  • Python应用指南:地铁两站之间最短路径查询
    随着城市交通的发展,地铁已成为许多城市居民日常出行的重要方式之一。地铁网络的复杂性和站点数量的增加使得乘客在选择最佳路线时面临挑战。为了帮助乘客快速、准确地找到从起始站到目的站的最短乘坐线路,本篇文章我们来求一下地铁两站之间最短路径查询的查询,通过Python脚本快......
  • 数据结构图的最短路径-弗洛伊德算法(有向图+数据结构课本C++代码一比一转C语言+邻接矩
    弗洛伊德算法有向图代码如下:#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<stdlib.h>#include<limits.h>#defineMaxInt32767#defineMVNum100intPath[MVNum][MVNum];//存放前驱索引的intD[MVNum][MVNum];//存放当前已知的权值//图的邻接......
  • 最短路算法笔记
    最短路算法最短路算法可大致分为三类:无负权边的单源最短路,有负权边的单源最短路和多源汇最短路dijkstra算法dijkstra算法是求无负权边的单源最短路的常用算法,基于贪心的思想其过程大致为:找到距离已经确定最短路的连通块的最近的点把他加入已经确定最短路的连通块用这个......
  • 【头歌实训:单源最短路径】
    头歌实训:单源最短路径给一个n(1≤n≤2500)个点m(1≤m≤6200)条边的无向图,求s到t的最短路。文章目录输入格式:输出格式:输出样例:注意:源代码:输入格式:第一行四个由空格隔开的整数n、m、s、t。之后的m行,每行三个正整数si、ti、wi(1≤wi≤......
  • CF35C. Fire Again 题解 bfs求最短路
    题目链接:https://codeforces.com/problemset/problem/35/C视频讲解:https://www.bilibili.com/video/BV1tZ1FYPELp/?p=4以每个着火的点为起点求最短路,然后输出任意一个距离值最大的点即可。需要注意的是:本题是文件输入输出。示例程序:#include<bits/stdc++.h>usingnamespace......
  • 【图论】(五)最短路径算法(D / BF / SPFA / F / A*)
    最短路径算法(D/BF/SPFA/F/A*)1.最短路径之dijkstra(D算法)思路模拟过程程序实现拓展2.dijkstra算法堆优化思路程序实现3.Bellman_ford算法(BF算法)松弛模拟过程拓展4.Bellman_ford队列优化算法(又名SPFA)模拟过程拓展5.Bellman_ford之判断负权回路思路拓展6......
  • Leetcode 1129. 颜色交替的最短路径
    1.题目基本信息1.1.题目描述给定一个整数n,即有向图中的节点数,其中节点标记为0到n–1。图中的每条边为红色或者蓝色,并且可能存在自环或平行边。给定两个数组redEdges和blueEdges,其中:redEdges[i]=[a_i,b_i]表示图中存在一条从节点a_i到节点b_i的红色有向边,bl......
  • 最短路默写
    有一无负权有向图。求指定两点间的最短路径。数据范围:所有数据不超过100直接最短路板子写上:#include<bits/stdc++.h>usingnamespacestd;constintN=510;intn,m;intg[N][N],dist[N];intx,y,z,s,t;boolvis[N];intDijkstra(ints,intt){ memset(dist,0x3f,siz......
  • 图论day64 :最短路径算法 | SPFA(Bellman_ford的队列优化版)、城市间货物运输 I、Ⅱ、Ⅲ
    图论day64:最短路径算法|SPFA(Bellman_ford的队列优化版)、94.城市间货物运输I(卡码网)【SPFA算法+邻接表优化】、95.城市间货物运输II(判断负权回路)、96.城市间货物运输III【已知有负权回路,该如何计算】、Bellman_ford算法思维导图汇总SPFA(Bellman_ford的队列优化版)94......