EK(轉) dinic(轉)
EK(未完)
以此份程式碼為例
//P3376 【模板】網路最大流
//EK演算法
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=410,M=10010;
int n,m,S,T,h[N],e[M],w[M],ne[M],idx,pre[N],dist[N],st[N],ans,g[N][N];
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
bool bfs(){
memset(st,0,sizeof st);
queue<int> q;
q.push(S);
st[S]=1;
dist[S]=(int)(1e18);
while(q.size()){
int t=q.front();q.pop();
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(!w[i]||st[j])continue;
dist[j]=min(dist[t],w[i]);
pre[j]=i;
st[j]=1;
q.push(j);
if(j==T)return 1;
}
}
return 0;
}
void update(){
int cur=T;
while(cur!=S){
int i=pre[cur];
w[i]-=dist[T];
w[i^1]+=dist[T];
cur=e[i^1];
}
ans+=dist[T];
}
signed main(){
memset(h,-1,sizeof h);
cin>>n>>m>>S>>T;
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
if(g[a][b])w[g[a][b]-2]+=c;
else{
add(a,b,c);
add(b,a,0);
g[a][b]=idx;
}
}
while(bfs())update();
cout<<ans;
} //by yjx
EK演算法單次bfs複雜度為 \(O(m)\)。
Dinic(未完)
#include<bits/stdc++.h>
#define fir first
#define se second
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
template <typename type>
inline void read(type &x) {
x=0; bool f=0; char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=(x<<3)+(x<<1)+(c^48);
c=getchar();
}
if(f) x=-x;
}
template <typename type,typename ...t>
inline void read(type &x,t &...te) {read(x); read(te...);}
const ll INF=0x3f3f3f3f3f3f3f3f;
const int N=210,M=1e4+50;
int n,m;
int head[N],nxt[M],to[M],W[M],num=1;
int S,T;
void add(int u,int v,int w) {
++num; nxt[num]=head[u]; to[num]=v; W[num]=w; head[u]=num;
++num; nxt[num]=head[v]; to[num]=u; W[num]=0; head[v]=num;
}
int cur[N],dep[N];
bool bfs() {
memset(dep,-1,sizeof(dep));
queue<int>q;
q.push(S);
cur[S]=head[S];
dep[S]=1;
while(!q.empty()) {
int u=q.front(); q.pop();
for(int i=head[u];i;i=nxt[i]) {
int v=to[i];
if(W[i]&&dep[v]==-1) {
dep[v]=dep[u]+1;
cur[v]=head[v];
if(v==T) return true;
q.push(v);
}
}
}
return false;
}
ll dfs(int u,ll lim) {
ll flow=0;
if(u==T) return lim;
for(int i=cur[u];i&&flow<lim;i=nxt[i]) {
int v=to[i];
cur[u]=i;
if(W[i]&&dep[v]==dep[u]+1) {
ll t=dfs(v,min(lim-flow,W[i]));
if(!t) dep[v]=-1;
W[i]-=t;
W[i^1]+=t;
flow+=t;
}
}
return flow;
}
int dinic() {
int ans=0,flow;
while(bfs())
while(flow=dfs(S,0x3f3f3f3f))
ans+=flow;
return ans;
}
signed main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
read(n,m,S,T);
for(int i=1;i<=m;i++) {
int u,v,w;
read(u,v,w);
add(u,v,w);
}
printf("%lld",dinic());
return 0;
}
Dinic演算法單次bfs複雜度為 \(\text{O}(m)\)
增廣輪數<=n
單輪增廣複雜度 \(\text{O}(nm)\)
下面我們來證明dinic增廣輪數<=n
首先dinic會按照層數分層,將長度最短的增廣路徑全部刪除,因此進行一遍dfs後,S到T在殘量網路上的距離將會改變。
現在我們證明每一次S到T在殘量網路上的距離將會增加1
設此時S到u經過若干條邊後聯通,S經過若干條邊與v聯通且dis(S,v)>dis(S,u)距離(不聯通也是相同道理,相當於在不經過u的情況下S到v的距離為INF),v經過若干條邊與T聯通,且S->u->v->T是最短的一條增廣路徑,而u->v是增廣路徑上邊權最小的邊。
經過一遍增廣後,此時殘量網路會變成這樣
此時S->u->v->T不聯通,而dis(S,v)>dis(S,u),因此新增v->u邊並不會讓S到T的距離更小。
因此只會讓S->T距離增大,且至少增加1。又因為dis(S,T)最大為n,因此增廣輪數最多為n。
下面我們來證單輪增廣複雜度 \(\text{O}(nm)\)
首先每次推流會清空至少一條邊u->v,而此時新增的反向邊不滿足dep[v]==dep[u]+1,因此最多清空 \(\text{O}(m)\) 次,對於清空每一條邊需要找到一條他所對應的增廣路,此時最多從S訪問到T,因此總複雜度為 \(\text{O}(mn)\)。
因此Dinic複雜度為 \(O(n^2m)\)。
(從複雜度分析就可很顯然地看出,Dinic複雜度在正常題目建圖情況下達不到該上界,因此總是跑得飛快)
by lyk
借鑑了[該地址](Dinic演算法複雜度證明 | yukiyama (iyukiyama.github.io))內容