题解 P4722 【模板】最大流 加强版 / 预流推进
2023.7.14 upd : 修改错别字。
本题目前理论复杂度最快方法。
超额缩放预流推进 EXCESS SCALING
全文
[3]A FAST AND SIMPLE ALGORITHM FOR THE MAXIMUM FLOW PROBLEM 1988
方法
Ahuja and Orlin 在 1988 年提出使用名为 Excess Scaling 的技巧把通用预流推进非饱和推流的次数从
类似 Binary Blcking Flow 算法对值域的缩放,我们进行
在一次 Scaling 中,我们只考虑超额流大于
在
在最多
具体的,我们使用链表对每个标号的超额流足够大的点进行存储,每次去有点的最小标号中任意点推一次流,并更新当前弧。
当一个点无法推流时重贴标签并重置当前弧。
本算法复杂度正确性基于无重边和自环,因此预处理合并重边,去掉自环。
伪代码
实现相关
该算法饱和推流一共
时间复杂度为
该算法按 OI 的简单化实现方式常数巨大无比,千万不要考场使用。
[评测记录]
#include <iostream>
#include <queue>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <map>
#include <ctime>
#define int long long
using namespace std;
int res=0;
int K,level;
const int inf=(long long)1<<40;
int n,m,s,t;
struct edge
{
int to,val,next;
}e[1200005];
int cnt=1,head[1200005],now[1200005];
void add(int x,int y,int z)
{
cnt++;
e[cnt].to=y;
e[cnt].val=z;
e[cnt].next=head[x];
now[x]=head[x]=cnt;
}
int h[120005],w[120005],cnth[120005];
queue<int>list[120005];
queue<int>qq;
int book[120005];
void bfs()
{
memset(h,0x3f,sizeof(h));
h[t]=0;
qq.push(t);
while(!qq.empty())
{
int u=qq.front();
qq.pop();
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(e[i^1].val&&h[u]+1<h[v])
{
h[v]=h[u]+1;
if(book[v]==0)
{
qq.push(v);
book[v]=1;
}
}
}
}
}
void push_relabel(int x,int Delta)
{
int i;
int found=0;
for(i=now[x];i;i=e[i].next)
{
int v=e[i].to;
if(h[x]==h[v]+1&&e[i].val)
{
found=1;
break;
}
else
{
now[x]=e[i].next;
}
}
if(found==1)
{
int v=e[i].to;
int flow=min(e[i].val,w[x]);
if(v!=t)flow=min(flow,Delta-w[v]);
e[i].val-=flow;
e[i^1].val+=flow;
w[x]-=flow;
w[v]+=flow;
if(w[x]<=Delta/2)list[level].pop();
if(w[v]>Delta/2&&v!=s&&v!=t)
{
list[h[v]].push(v);
level--;
}
}
else
{
res++;
list[level].pop();
cnth[level]--;
if(cnth[level]==0)
{
for(int i=1;i<=n;i++)
{
if(h[i]>level&&i!=s&&i!=t&&h[i]<n+1)
{
h[i]=n+1;
}
}
}
int minn=inf;
for(int i=head[x];i;i=e[i].next)
{
int to=e[i].to;
if(e[i].val)
{
minn=min(minn,h[to]);
}
}
h[x]=minn+1;
if(minn==inf)h[x]=n+1;
if(h[x]<=1200000)cnth[h[x]]++;
if(h[x]<=1200000)list[h[x]].push(x);
now[x]=head[x];
}
}
int Excess_Scaling()
{
bfs();
if(h[s]==0x3f3f3f)return 0;
h[s]=n;
for(int i=1;i<=n;i++)
{
if(h[i]<0x3f3f3f)
{
cnth[h[i]]++;
}
}
for(int i=head[s];i;i=e[i].next)
{
int to=e[i].to,val=e[i].val;
if(val)
{
e[i].val-=val;
e[i^1].val+=val;
w[s]-=val;
w[to]+=val;
}
}
for(int k=1;k<=K;k++)
{
int Delta=(long long)1<<(K-k);
for(int i=1;i<=n;i++)
{
if(w[i]>Delta/2)
{
if(h[i]<=1200000)list[h[i]].push(i);
}
}
level=1;
while(level<=n)
{
if(list[level].empty())level++;
else
{
int x=list[level].front();
push_relabel(x,Delta);
}
}
for(int i=1;i<=32;i++)
{
while(!list[i].empty())
{
list[i].pop();
}
}
}
return w[t];
}
signed main()
{
int i,j,k;
ios::sync_with_stdio(0);
cin>>n>>m>>s>>t;
for(i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
if(x==y)continue;
add(x,y,z);
add(y,x,0);
}
K=31;
cout<<Excess_Scaling();
return 0;
}