Johnson 全源最短路算法以及 Primal-Dual 原始对偶算法
Johnson 全源最短路算法
引入:多源最短路问题,设点数为
我们有如下方案:
- floyd,时间复杂度
,适合任意图。 - Bellman-ford(SPFA),时间复杂度
,适合任意图。 - Dijkstra,时间复杂度
,适合非负权图。
综上分析,我们发现:Dijkstra 的时间复杂度最优,但适用范围较小,不能处理负权图。
那有没有办法使得 Dijkstra 能在负权图上运行呢?可以。
考虑给每个点设置一个势能
势能还有一个特点,势能的绝对值往往取决于设置的零势能点,但无论将零势能点设置在哪里,两点间势能的差值是一定的。
我们随便令一个点为虚拟起点,以该点为起点跑 Bellman-ford,虚拟起点到每个点的最短路即为每个点的势能。
在最短路问题中,我们令一条有向边
正确性证明:
- 求得的最短路大小与路径上的其他点无关:假设起点为
,令中间经过的点依次为 ,权值依次为 ,那么最终求得的最短路为 。 - 所有边的权值均非负:因为初始的势能是最短路求得的,而最短路满足三角形不等式
,也即 。
Primal-Dual 原始对偶算法
或许前面只是引子?
前置知识:基本费用流算法(好像叫 SSP?),Johnson 全源最短路算法。
众所周知,基本的费用流算法是每次用最短路算法找出一条边权最小的增广路径,直到原图不存在增广路径为止。由于费用流建图上会有反边(也即边权为负数的边),所以不能用 Dijkstra 求解最短路,只能使用 Bellman-ford 或者 SPFA,时间复杂度
但有些题目会丧心病狂的卡 SPFA,这时候基本的费用流算法会 TLE。
这个时候我们需要使用 Johnson 全源最短路算法的思想来把边权转化为非负权,从而可以使用 Dijkstra 求最短路,把时间复杂度优化至
仍然先跑一遍 Bellman-ford,势能的设置同 Johnson。但每次增广的话,图的形态会发生改变,那么新势能该如何设置呢?
设增广后从起点(也就是源点)的最短路为
正确性证明:
- 求得的最短路大小与路径上的其他点无关:同理。
- 所有边的权值均非负:考虑因为增广使得多出了一些边
,那么一定满足 (否则 不在增广路上),因为初始的 ,所以有 ,所以 。
时间复杂度
参考代码(省略初始化代码):
int S,T;
struct edge{
int to,nxt,w,c;
}a[maxm];
int head[maxn],edges;
void add(int x,int y,int z,int w){
a[++edges]=(edge){y,head[x],z,w};
head[x]=edges;
}
void add_edge(int x,int y,int z,int w){
add(x,y,z,w),add(y,x,0,-w);
}
int dis[maxn],dinic[maxn];
int h[maxn];
int pre[maxn],e[maxn];
bool dij(){
rep(i,1,T)dis[i]=dinic[i]=llinf,vis[i]=0;
priority_queue<pii,vector<pii>,greater<pii> >q;
dis[S]=0,q.push(mp(0,S));
while(!q.empty()){
pii nw=q.top();q.pop();
if(vis[nw.se])continue;vis[nw.se]=1;
graph(i,nw.se,head,a){
int u=a[i].to,exdis=a[i].c+h[nw.se]-h[u];
assert(!a[i].w||exdis>=0);
if(a[i].w&&dis[u]>nw.fi+exdis){
dis[u]=nw.fi+exdis,dinic[u]=min(dinic[nw.se],a[i].w),pre[u]=nw.se,e[u]=i;
q.push(mp(dis[u],u));
}
}
}
return vis[T];
}
int EK(){
int res=0,flow=0;
while(dij()){
flow+=dinic[T];
assert(h[S]==0);
res+=dinic[T]*(dis[T]+h[T]);
rep(i,1,T)h[i]+=dis[i];
int p=T;
while(p^S){
a[e[p]].w-=dinic[T],a[e[p]^1].w+=dinic[T];
p=pre[p];
}
}
return res;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?