当前位置: 首页 > news >正文

最短路拓展

最短路拓展

0X01 分层图最短路

题目

我们可以把这种有 \(k\) 次把 \((u,v)\) 改变成 \(w\) 题目叫做 分层图最短路

你还记得 Dijkstra 吗 对!我们可以仿照 Dijkstra 的思路 从起点 \(s\) 开始跑一遍最短路然后返回 \(l_t\)

但有个问题来了 我们有 \(k\) 次改变边权的机会啊

那我们是不是可以把改变了 \(a\) 次后的图存下来在和改变 \(a-1\) 后的图拼接起来呢

没错 这就是分层图最短路 可能单说理解不了 那看 code

code:

//LG
//[JLOI2011] 飞行路线
//https://www.luogu.com.cn/problem/P4568
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct e{int u,v;int w;
};
vector<e> G[110010];
int n,m,k,s,t;
int Dijkstra(int s,int t){vector<int> l(n*(k+1)+10,INT_MAX);l[s]=0;vector<bool> f(n*(k+1)+10,1);priority_queue<pair<int,int> > q;q.push(make_pair(0,s));while(q.size()){int u=q.top().second;q.pop();if(f[u]){f[u]=0;for(int j=0;j<G[u].size();j++){int v=G[u][j].v,w=G[u][j].w;if(l[v]>l[u]+w){l[v]=l[u]+w;q.push(make_pair(-l[v],v));}}}}int ans=INT_MAX;for(int i=0;i<=k;i++)ans=min(ans,l[t+i*n]);return ans;
}
int main(){cin>>n>>m>>k;cin>>s>>t;while(m--){int u,v,w;cin>>u>>v>>w;for(int i=0;i<=k;i++){G[u+i*n].push_back({u+i*n,v+i*n,w});G[v+i*n].push_back({v+i*n,u+i*n,w});}for(int i=0;i<k;i++){G[u+i*n].push_back({u+i*n,v+(i+1)*n,0});G[v+i*n].push_back({v+i*n,u+(i+1)*n,0});}}cout<<Dijkstra(s,t);return 0;
}

可以看到 整个 Dijkstra 是没有变的 重要的部分是

for(int i=0;i<=k;i++){G[u+i*n].push_back({u+i*n,v+i*n,w});G[v+i*n].push_back({v+i*n,u+i*n,w});
}
for(int i=0;i<k;i++){G[u+i*n].push_back({u+i*n,v+(i+1)*n,0});G[v+i*n].push_back({v+i*n,u+(i+1)*n,0});
}

这就是新建改变了 \(a\) 次后的图再和改变 \(a-1\) 后的图拼接起来

除了这种解法还有一种DP的解法不太会用到就不讲了 有兴趣可以看看我写的 code

code:

//LG
//[JLOI2011] 飞行路线
//https://www.luogu.com.cn/problem/P4568
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct e{int u,v;int w;
};
vector<e> G[110010];
int n,m,k,s,t;
int Dijkstra(int s,int t){vector<vector<int> > l(n+10,vector<int>(k+1,INT_MAX));l[s][0]=0;vector<vector<bool> > f(n+10,vector<bool>(k+1,1));priority_queue<pair<int,pair<int,int> > > q;q.push(make_pair(0,make_pair(s,0)));while(q.size()){int u=q.top().second.first,cnt=-q.top().second.second;q.pop();if(f[u][cnt]){f[u][cnt]=0;for(int j=0;j<G[u].size();j++){int v=G[u][j].v,w=G[u][j].w;if(l[v][cnt]>l[u][cnt]+w){l[v][cnt]=l[u][cnt]+w;q.push(make_pair(-l[v][cnt],make_pair(v,-cnt)));}if(cnt<k&&l[v][cnt+1]>l[u][cnt]){l[v][cnt+1]=l[u][cnt];q.push(make_pair(-l[v][cnt+1],make_pair(v,-(cnt+1))));}}}}int ans=INT_MAX;for(int i=0;i<=k;i++)ans=min(ans,l[t][i]);return ans;
}
int main(){cin>>n>>m>>k;cin>>s>>t;while(m--){int u,v,w;cin>>u>>v>>w;G[u].push_back({u,v,w});G[v].push_back({v,u,w});}cout<<Dijkstra(s,t);return 0;
}

0x02 负环

在讲单元最短路时讲过在求最短路时不能出现负环

那我们样如何判断负环呢

首先我们要知道一条最短路径一定是一条(废话

的长度不会超过 \(V-1\) 条边

所以我们可以在做 SPFA 时记录从 \(s\)\(i\) 的最短路径上有几条边 记作 \(cnt_i\) 如果有负环那 \(cnt_i\) 会一直增加最后超过 \(n-1\) 这样就可以判断负环了

为什么用 SPFA

这时有人会问了SPFA不死了吗? 干嘛用它啊?那我们看看其他算法是否可以1. Dijkstra 这个不能在负权图上 淘汰
2. Floyd $\mathcal{O}(n^3) $ 不如 SPFA 淘汰
3. Bellman-Ford SPFA是它的优化 不如 SPFA 淘汰好吧 看来SPFA是最好的了

code:

//LG
//【模板】负环
//https://www.luogu.com.cn/problem/P3385
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
struct e{int u,v,w;
};
vector<e> G[2010];
int n,m,T;
ll SPFA(){vector<int> l(n+10,INT_MAX);l[1]=0;vector<int> cnt(n+10,0);vector<bool> f(n+10,1);f[1]=0;queue<int> q;q.push(1);while(q.size()){int u=q.front();q.pop();f[u]=1;for(int i=0;i<G[u].size();i++){int v=G[u][i].v,w=G[u][i].w;if(l[v]>l[u]+w){cnt[v]=cnt[u]+1;l[v]=l[u]+w;if(f[v]){q.push(v);f[v]=0;}}if(cnt[v]>=n)return 0;}}return 1;
}
int main(){cin>>T;while(T--){cin>>n>>m;for(int i=1;i<=n;i++)G[i].clear();while(m--){int u,v,w;cin>>u>>v>>w;if(w>=0){G[u].push_back({u,v,w});G[v].push_back({v,u,w});}else{G[u].push_back({u,v,w});}}cout<<(SPFA()?"NO\n":"YES\n");}return 0;
}

0x03 差分约束

这是有人问了(没有

判断有没有负环 有啥用啊

它有个十分强大的用处就是解像这样的不等式

\[\left\{\begin{matrix} x_{c_1}-x_{c_1'} \le y_1 \\ x_{c_2}-x_{c_2'} \le y_2 \\ x_{c_3}-x_{c_3'} \le y_3 \\\vdots \\ x_{c_n}-x_{c_n'} \le y_n \\ \end{matrix}\right. \]

这和最短路有啥关系啊?

其实它的每一条都很想松弛的条件你看 $x_{c_i}\le y_i+x_{c_i'} $ 和 \(l_v \le l_u + (u,v)\)

所以说 我们可以设计一条 \(x_{c_i'}\)\(x_{c_i}\) 的一条边权为 \(y_i\) 的边 然后跑一次 SPFA 如果有负环 就无解 否则 \(l\) 就是解

http://www.jsqmd.com/news/591891/

相关文章:

  • Phi-3-mini-4k-instruct在Matlab科学计算中的集成应用
  • 多模型生成效果横向对比:Qwen-Image-Edit-F2P在写实人像领域的优势分析
  • 暗黑破坏神2存档修改与角色调整工具:安全高效的d2s文件编辑解决方案
  • 手把手教学:用vLLM-v0.17.1快速搭建你的第一个LLM服务
  • 用快马平台快速原型设计:五分钟打造动态魔鬼面具3D展示页
  • 智能歌词工具:四大维度解决音乐歌词管理难题
  • ide-eval-resetter:JetBrains IDE试用期重置工具的全面应用指南
  • 告别手动群发:如何用连趣云实现企业微信/钉钉/飞书消息定时自动推送?
  • 368个地级市异质性分析实战指南:Excel、DTA与DO文件的高效应用
  • 基于C#的Socket通讯,实现客户端和服务器互相通讯 一瓶水的价格,掌握一个知识点 功能包含...
  • 工作隐私防护新选择:Boss-Key窗口管理工具深度解析
  • Ultimaker Cura:3D打印切片软件的5个核心功能深度解析与实战指南
  • 为何说逻辑回归是分类任务的“最佳基石”?
  • YimMenu:重新定义GTA5体验的全能工具包
  • FLUX.1-dev FP8量化模型:如何在6GB显存设备上体验专业AI绘画的终极指南
  • 从安装到投产:企业级AI编程工具落地全流程避坑指南(以文心快码私有化部署为例)
  • 2026重庆英语培训机构排名,北外壹佳英语上榜了吗 - mypinpai
  • 如何快速掌握MapleStory游戏资源编辑:Harepacker-resurrected完整实战指南
  • Ostrakon-VL-8B行业落地:药房阴凉区温湿度标识+药品有效期双识别案例
  • OpCore-Simplify:黑苹果配置自动化的架构设计与技术实现
  • 2026年重庆好用的少儿英语机构有哪些,剑桥体系品牌推荐 - 工业品牌热点
  • 3分钟掌握终极iOS应用下载:ipatool命令行工具完全指南
  • MAA助手全平台实战部署从入门到精通
  • WeMod增强工具技术架构实现方案:基于ASAR解包与运行时注入的客户端增强方案
  • 基于数据预处理与PSO-SVM的风功率预测聚类研究
  • 3分钟解锁网易云音乐NCM格式:ncmdumpGUI图形界面工具深度解析
  • 智能网页数据获取:Crawl4AI v1.0.0全攻略
  • 从感知机到GPT:一个1957年的“神经元”如何引爆2026年的AI革命?
  • HarmonyOS蓝牙SPP实战:5分钟搞定设备间文件传输(附完整代码)
  • 聊聊2026年江苏好用的工装定制企业,推荐售后完善的常州千诺 - myqiye