最短路算法
本篇文章将介绍一些关于最短路的基本算法.
Floyd算法
处理全源最短路问题,时间复杂度较高,容易实现,时间复杂度
//n表示节点总数,f[i][j]表示i到j的最短路径 for(int k=1;k<=n;k++){//表示仅允许经过节点1-k for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ f[i][j]=min(f[i][j],f[i][k]+f[k][j]);//比较经过k点与不经过k点的最短路 } } }
Bellman_ford算法
基于松弛原理的算法,可以带负边权.
松弛原理即对于边
设这个图有
因为此算法时间复杂度与队列优化后的SPFA算法的最坏时间复杂度相同,所以可以优先使用SPFA算法的代码,Bellman_ford算法代码实现略.
此算法可以判断负环,如果第
SPFA算法
Bellman_ford算法的队列优化,我们发现不是每个点都需要松弛,而是被松弛后的点所连接的边才可能引起下一次松弛,我们用队列记录可能被松弛的点.
SPFA算法同样也可以判断负环,需要记录最短路经过多少边,如果最短路经过
此算法的最坏时间复杂度为
struct edge{ int v,w; }g[N]; int dis[N],vis[N],cnt[N]; queue<int>q; bool spfa(int s,int n){ memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); dis[s]=0; q.push(s); vis[s]=1; while(!q.empty()){ int u=q.front();q.pop(); vis[u]=0; for(auto x:g[u]){ int v=x.v;w=x.w; if(dis[v]>dis[u]+w){//松弛操作 dis[v]=dis[u]+w; cnt[v]=cnt[u]+1;//记录最短路边数 if(cnt[v]>=n) return false;//判断负环 if(!vis[v]) q.push(v),vis[v]=1; } } } return true; }
Dijkstra算法
同样要用到松弛原理,只能在非负边权图中使用.
考虑一种贪心,我们定义集合
我们可以证明当前贪心策略正确,因为全局的边权都为非负数,全局最小值无法被其他节点更新,所以当我们找到dis值最小的点时,他已经是起点到此点的最短路径,我们不断用全局最小值进行拓展,最终可以得到所有点的最短路径.
在稠密图时可直接运用暴力做法做最优,时间复杂度为
下面仅给出实现难度略大的优先队列优化做法.
struct node{ int u,v,w; }; vector<node> g[N]; int vis[N],dis[N]; struct T{ int d,u; friend bool operator<(T a,T b){ //重构运算符<(重构>会编译错误),因为优先队列默认从大到小排序,相反重构可以让他从小到大排序 return a.d>b.d; } }; priority_queue< T > q; void dijkstra(int start){ memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); dis[start]=0;//初始化起点的dis值为0 q.push((T){0,start});// while(!q.empty()){ T t=q.top(); q.pop();//取出当前路径最短的点 int u=t.u; if(vis[u]) continue;//如果该点已经找到最短路径则无须在继续 vis[u]=1;//标记此点已经找到最短路径 for(auto e:g[u]){ int v=e.v,u=e.u; if(dis[v]>e.w+dis[u]){//松弛操作 dis[v]=e.w+dis[u]; q.push((T){dis[v],v});//将得到路径长度的点放入优先队列 } } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】