首页 > 其他分享 >最短路相关技术

最短路相关技术

时间:2024-12-23 10:57:36浏览次数:4  
标签:int 短路 技术 负环 vis maxn 相关 dis

板子是一定要记的,但不够,全是思维题,要解放思想开动脑筋。

板子

Floyd

是全源最短路。

只要最短路存在(无负环),不管有向无向,边权正负,都可以用。

板子
for(int k=1;k<=n;++k){
  for(int i=1;i<=n;++i){
    for(int j=1;j<=n;++j)
      dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
      \\dis[k][i][j]=min(dis[k-1][i][j],dis[k-1][i][k]+dis[k-1][k][j]);
  }
}

本质是一个DP。

\(O(n^3)\)

Dijkstra

是单源最短路。

只适用于非负权图

  • 暴力做\(O(n^2)\)(适合稠密图)

  • 线段树/二叉堆优化\(O(m\log n)\)(适合稀疏图)

  • 堆优化\(O(m\log m)\)(适合稀疏图)

堆优化板子(最好写的一个)
priority_queue< pair<int,int> > q;//默认的是大根堆,所以下方dis[v]取相反数。
scanf("%d%d",&s,&t);
for(int i=0;i<=n;++i) dis[i]=inf;
dis[s]=0;
q.push(make_pair(0,s));
while(!q.empty()){
	int u=q.top().second;
	q.pop();
	if(vis[u]) continue;
	vis[u]=true;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].v,w=e[i].w;
		if(dis[v]>dis[u]+w){
			dis[v]=dis[u]+w;
			q.push(make_pair(-dis[v],v));
		}
	}
}
暴力板子
for(int u=1;u<=n;u++){
	dis[u]=inf;
	vis[u]=false;
}
dis[s]=0;
for(int i=1;i<=n;i++){
	int minx=inf,u=0;
	for(int v=1;v<= n;v ++){
		if(vis[v]||dis[v]>minx) continue;
		minx=dis[v],u=v;
	}
	vis[u]=1;
	for(int j=head[u];j;j=e[j].nxt){
		int v=e[j].v,w=e[j].w;
		if(dis[v]<dis[u]+w) continue;
		dis[v]=dis[u]+w;
	}
}
线段树优化板子
#include<bits/stdc++.h>

using namespace std;

const int maxn=1e5+10,maxm=2e5+10,inf=1e9+7;
int n,m,tot,s,head[maxn],dis[maxn],mi[maxn<<2];
struct edge{
	int v,w,nxt;
}e[maxm];

void add(int u,int v,int w){
	e[++tot].v=v;
	e[tot].w=w;
	e[tot].nxt=head[u];
	head[u]=tot;
}

#define ls(k) k<<1
#define rs(k) k<<1|1

void pushup(int k){
	mi[k]=min(mi[ls(k)],mi[rs(k)]);
}

void build(int k,int l,int r){
	mi[k]=inf;
	if(l==r) return;
	int mid=l+r>>1;
	build(ls(k),l,mid);
	build(rs(k),mid+1,r);
	pushup(k);
}

void upd(int k,int l,int r,int p,int v){
	if(l==r){
		mi[k]=v;
		return;
	}
	int mid=l+r>>1;
	if(p<=mid) upd(ls(k),l,mid,p,v);
	else upd(rs(k),mid+1,r,p,v);
	pushup(k);
}

int query(int k,int l,int r){
	if(l==r) return l;
	int mid=l+r>>1;
	if(mi[ls(k)]<=mi[rs(k)]) return query(ls(k),l,mid);
	else return query(rs(k),mid+1,r);
}

\\其实就是用线段树做优先队列在做的事情。
\\线段树维护的是还未确定最短路的集合,inf即可以表示已经被移出了该集合,也可以表示最开始初始化的最短路长度。
\\每次移出该集合中最短路最小的点,并用这个点的出边进行松弛操作。

void dijkstra(){
	for(int i=1;i<=n;++i) dis[i]=inf;
	build(1,1,n);
	upd(1,1,n,s,0);
	dis[s]=0;
	while(mi[1]^inf){
		int u=query(1,1,n);
		upd(1,1,n,u,inf);
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].v,w=e[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				upd(1,1,n,v,dis[v]);
			}
		}
	}
}

int main(){
	scanf("%d%d%d",&n,&m,&s);
	for(int i=1;i<=m;++i){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	dijkstra();
	for(int i=1;i<=n;++i) printf("%d ",dis[i]);
	return 0;
} 

Bellman-Ford和SPFA

这两个都可以处理带负权的图上的最短路,并且可以判断最短路是否存在(判断负环)

SPFA是Bellman-Ford的队列优化。

Bellman-Ford是在每轮循环中对每条边尝试松弛,每轮松弛至少使最短路长度\(+1\),所以最多进行\(n-1\)轮。\(O(nm)\)。

显然只有在上一次被松弛过的点所连的边才可能引起下次松弛,用队列存一下,每次只松弛必要的边,就得到了SPFA。

SPFA大多数时候跑得比较快,但最坏\(O(nm)\),要小心使用尽量别用。SPFA容易被卡,但费用流要用

判断负环:记录一下最短路经过了几条边,当最短路至少经过\(n\)条边时,就说明可以抵达负环(因为如果没有负环,最短路最多经过\(n-1\)条边)。

注意这里只能判断从起点\(s\)出发能否抵达负环。若图不保证连通,要判断是否存在负环,则要建立一个超级源点\(S\),从\(S\)向每个点连边(边权为\(0\)),再跑SPFA。

SPFA判断负环板子
bool spfa(int n, int s){
  for(int i=1;i<=n;++i) dis[i]=inf;
  dis[s]=0,inque[s]=1;
  q.push(s);
  while(!q.empty()){
    int u=q.front();
    q.pop();
    inque[u]=0;
    for(int i=head[u];i;i=e[i].nxt){
      int v=e[i].v, w=e[i].w;
      if(dis[v]>dis[u]+w){
        dis[v]=dis[u]+w;
        cnt[v]=cnt[u]+1; 
        if(cnt[v]>=n) return false;
        if(!inque[v]) q.push(v), inque[v]=1;
      }
    }
  }
  return true;
}

Johnson

能处理无负环图上的全源最短路。

流程:

  1. 建立超级源点\(S\)向每个点连边,边权为\(0\).
  2. 以\(S\)为起点跑一遍SPFA,求出到每个点\(i\)的最短路\(h_i\)
  3. 对于一条起点为\(u\),终点为\(v\),边权为\(w\)的边,重新设置边权为\(w+h_u-h_v\)。
  4. 这样就保证了边权非负,以每个点为起点跑\(n\)轮Dijkstra即可。
  5. 最终求出\(u\)到\(v\)的最短路为\(dis_{u,v}\),则原来\(u\)到\(v\)的最短路为\(dis_{u,v}+h_v-h_u\)。若\(dis_{u,v}=inf\),则\(u\)不可到达\(v\)。

当Dijkstra使用堆优化时,Johnson的时间复杂度为\(O(nm\log m)\),在稀疏图上比Floyd好。

Johnson全源最短路模板题

板子
#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

const int maxn=3e3+10,maxm=6e3+10,inf=1e9;
int n,m,tot=0,head[maxn],cnt[maxn];
bool vis[maxn];
ll ans=0,dis[maxn],h[maxn];
struct edge{
	int u,v,w,nxt;
}e[maxm+maxn];

void add(int u,int v,int w){
	e[++tot].u=u;
	e[tot].v=v;
	e[tot].w=w;
	e[tot].nxt=head[u];
	head[u]=tot;
}

void spfa(){
	memset(h,0x3f3f3f3f,sizeof h);
	queue<int> q;
	h[0]=0,vis[0]=true;
	q.push(0);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].v,w=e[i].w;
			if(h[v]>h[u]+w){
				h[v]=h[u]+w;
				cnt[v]=cnt[u]+1;
				if(cnt[v]>n){
					puts("-1");
					exit(0);
				}
				if(!vis[v]){
					q.push(v);
					vis[v]=true;
				}
			}
		}
	}
}

void dijkstra(int s){
	for(int i=1;i<=n;++i) vis[i]=false,dis[i]=inf;
	dis[s]=0;
	priority_queue< pair<ll,int> > q;
	q.push(make_pair(0,s));
	while(!q.empty()){
		int u=q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u]=true;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].v,w=e[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push(make_pair(-dis[v],v));
			}
		}
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	for(int i=1;i<=n;++i) add(0,i,0);
	spfa();
	for(int i=1;i<=tot;++i){
		int u=e[i].u,v=e[i].v;
		e[i].w+=h[u]-h[v];
	}
	for(int i=1;i<=n;++i){
		dijkstra(i);
		ans=0;
		for(int j=1;j<=n;++j){
			if(dis[j]==inf) ans+=1ll*j*inf;
			else ans+=1ll*j*(dis[j]+h[j]-h[i]);
		}
		printf("%lld\n",ans);
	}
	return 0;
} 

各种技术

标签:int,短路,技术,负环,vis,maxn,相关,dis
From: https://www.cnblogs.com/EmilyDavid/p/18623406

相关文章

  • 揭示Newman教授的错误:Dijkstra算法的松弛次序与最短路径中的边次序不一定相同
    揭示Newman教授的错误:Dijkstra算法的松弛次序与最短路径中的边次序不一定相同Dijkstra算法简介Newman教授的观点反驳观点示例图Dijkstra算法的执行过程分析松弛次序与最短路径中的边次序结论C语言实现Dijkstra算法在探讨Dijkstra算法的松弛次序是否一定与最......
  • 最小生成树相关技术
    注意只有连通图才有生成树,图不连通就只有生成森林。最小生成树的板子Kruskal基本思想是按边权从小到大加边,是贪心思想。时间复杂度\(O(m\logm)\)。板子sort(e+1,e+tot+1,cmp);for(inti=1;i<=tot;++i){ intu=e[i].u,v=e[i].v; u=find(u),v=find(v); if(u==v)continu......
  • 深入探索人工智能的技术热点:生成式AI、强化学习与AI算法优化
    人工智能(AI)技术在不断发展中,带来了许多突破性的进展。我们看到了生成式AI在图像、文本生成等领域的广泛应用,也见证了强化学习在复杂决策问题中的成功实践。同时,随着AI技术逐渐走向实际应用,算法优化与效率提升成了新的技术焦点。在这篇博客中,我们将重点讨论目前在人工智能领域的......
  • .NET 9 New features-AOT相关的改进
    上一篇文章给大家介绍了.NET9Newfeatures-JSON序列化 本篇文章,研究分享一下关于AOT方面的改进1.什么是AOTAOT(Ahead-of-Time)编译是一种在应用程序部署之前,将高级语言代码直接编译为本机机器代码的技术。与传统的即时编译(Just-In-Time,JIT)不同,AOT在应用程序运行之前完成编......
  • 汽车电子技术框架
    0Preface写在汽车行业发展的拐点。最近这十年,汽车行业已经从传统行业一跃转变为高科技产业。随着电动化和智能化的发展,汽车形态已经从传统的燃油车转变为智能终端。同时,汽车已经从硬件主导转变为软件定义,最近随着AI大模型的突破,隐隐的升级为AI定义汽车。技术的发展对于传统......
  • 什么是RIAD技术?
    RAID(RedundantArrayofIndependentDisks)即独立磁盘冗余阵列,是一种把多个独立的物理磁盘按不同的方式组合起来形成一个逻辑磁盘阵列的技术,以下是详细介绍:一、RAID的主要目的1、提高性能        通过数据条带化(DataStriping)来实现。例如,在RAID0中,数据被分割成......
  • "该系统对指定的帐户没有授权,因此无法完成此操作。请使用与此帐户相关联的提供程序重
    使用net命令改不了用户口令通过mmc添加用户管理模块没有在计算机管理中也没有用户管理查看设置里目前只用了这两种登录方式并且下面的“仅允许使用windowshello登录”是打开的当关掉上面选项后就出现密码登录功能了......
  • 基于HarmonyOS 5.0的元服务:技术架构、应用场景与未来发展【探讨】
    基于HarmonyOS5.0的元服务:技术架构、应用场景与未来发展【探讨】引言随着数字化技术的不断进步,智能设备的互联互通成为科技发展的主流方向。华为的HarmonyOS5.0系统在这一趋势下推出了创新性的“元服务”概念。元服务(SuperService)是鸿蒙系统中的一种新型服务架构,旨在为用户......
  • 【PHP安全】php程序源码保护技术
    一、基本介绍二、加密方式2.1源码混淆处理2.1.1PHP威盾混淆2.1.2php-obfuscator2.2YAKPro混淆处理2.3源码外壳加密2.3.1PHPEval加密2.3.2PHPEval变异2.3.3phpjiami处理2.4源码扩展加密2.4.1ph......
  • 免费下载 | GBT 44109 2024 信息技术 大数据 数据治理实施指南
    GB/T44109—2024《信息技术大数据数据治理实施指南》提供了大数据环境下数据治理实施的过程指南,包括规划、执行、评价和改进四个过程的相关活动及内容。适用于指导组织开展数据治理实施工作。以下是该标准的核心内容概述:1.范围提供大数据环境下数据治理实施的过程指南......