演算法執行過程見藍書和OI-wiki,當前弧最佳化見OI-wiki的描述,程式碼見下
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=10010,M=100010,inf=1<<29;
int now[N],End[M<<1],Next[M<<1],Len[M<<1],Last[N];
int n,m,s,t,cnt=1,d[N];
ll maxflow=0;
queue<int> q;
void add(int x,int y,int z)
{
End[++cnt]=y,Next[cnt]=Last[x],Len[cnt]=z,Last[x]=cnt;
End[++cnt]=x,Next[cnt]=Last[y],Len[cnt]=0,Last[y]=cnt;
}
bool bfs()//構建分層圖
{
while(!q.empty()) q.pop();
memset(d,0,sizeof(d));//d表示層次
q.push(s),d[s]=1;
now[s]=Last[s];//now是當前弧最佳化
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=Last[x];i;i=Next[i])
{
int y=End[i];
if(!Len[i]||d[y]) continue;
q.push(y),d[y]=d[x]+1;
now[y]=Last[y];//構建分層圖的時候,初始化當前弧
if(y==t) return 1;
}
}
return 0;
}
int dinic(int x,int flow)//dinic(x,flow)表示有flow流量流進x,最多有多少流量可以從x流出到t
{
if(x==t) return flow;
int rest=flow,k,i;//rest表示還沒有分配的剩餘的流量
for(i=now[x];i&&rest;i=Next[i])
if(Len[i]&&d[End[i]]==d[x]+1)//如果是分層圖上面的邊
{
now[x]=i;
//當前弧最佳化
//對於上一條分層圖的邊
//如果我們分配的流量是rest(也就是說rest<len)
//那麼就說明我們分配小於rest的流量就可以讓上一條邊堵塞(因為rest為0的話就會結束迴圈)
//所以接下來就都不用考慮上一條邊了,因為一定已經堵塞了
//如果我們分配的流量是len(也就是說rest>len)
//那麼無論len是否被用完,都可以說明上一條邊堵塞了,也不用考慮了
//如果將當前弧最佳化放在`return flow-rest`的上面一句
//那麼當前這個分層圖一定只會dfs到x這個點一次
//就會導致外面構建分層圖的bfs執行更多次
//於是TLE
//所以當前弧最佳化要放在這個位置
k=dinic(End[i],min(rest,Len[i]));
if(!k) d[End[i]]=0;//如果一點流量都流不出去,直接刪除這條邊
Len[i]-=k;
Len[i^1]+=k;//更新殘存網路
rest-=k;
}
return flow-rest;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
add(u,v,c);
}
int flow;
while(bfs())
while(flow=dinic(s,inf))//其實這個while可以改成if,因為初始流量為無窮,走一遍就可以把每條以s為起點的邊流堵塞;也就是說這個while只會執行一次
maxflow+=flow;
printf("%lld",maxflow);
return 0;
}