网络最大流dinic算法

题目描述

如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。

输入输出格式

输入格式:

第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

接下来M行每行包含三个正整数ui、vi、wi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi)

输出格式:

一行,包含一个正整数,即为该网络的最大流。

输入输出样例

输入样例#1:
4 5 4 3
4 2 30
4 3 20
2 3 20
2 1 30
1 3 40
输出样例#1:
50

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=25

对于70%的数据:N<=200,M<=1000

对于100%的数据:N<=10000,M<=100000

样例说明:

题目中存在3条路径:

4-->2-->3,该路线可通过20的流量

4-->3,可通过20的流量

4-->2-->1-->3,可通过10的流量(边4-->2之前已经耗费了20的流量)

故流量总计20+20+10=50。输出50。

    先讲一下dinic的思路。

    与EK、FF相同,dinic也是通过找增广路来完成的。但与前两者不同的是,dinic是通过

bfs把图分层,再找多条路径长度相同的增广路,再重复操作。

    另外,dinic找的增广路都是最短的,这样时间复杂度就会对?这可能比较玄学,具体的原理

和证明我也不太清楚。

    下面是代码。

#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define INF 2147483647
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct edge{
    int head,next,to,b;
}f[400000];
int tot,n,m,s,t;
int mark[100000],dep[100000];
long long ans;
void add(int u,int v,int w){
    f[tot].next=f[u].head;f[u].head=tot;f[tot].to=v;f[tot].b=w;tot++;
}
bool bfs(){
    memset(mark,0,sizeof(mark));
    memset(dep,0,sizeof(dep));
    queue<int>Q; Q.push(s);
    dep[s]=1; mark[s]=1;
    while(!Q.empty()){
        int x=Q.front(); Q.pop();
        for(int i=f[x].head;i!=-1;i=f[i].next){
            int p=f[i].to;
            if(mark[p]||!f[i].b) continue;
            mark[p]=1;
            dep[p]=dep[x]+1;
            Q.push(p);
        }
        if(mark[t]) return 1;
    }
    return 0;
}
int dfs(int x,int a){
    if(x==t) return a;
    int flow=0;
    for(int i=f[x].head;i!=-1;i=f[i].next){
        int p=f[i].to;
        if(dep[p]!=dep[x]+1||!f[i].b) continue;
        int delta=dfs(p,min(a,f[i].b));
        flow+=delta;
        a-=delta;
        f[i].b-=delta;
        f[i^1].b+=delta;
        if(!a) break;
    }
    return flow;
}
void dinic(){
    while(bfs()) ans+=dfs(s,INF);
}
int main(){
    n=read();m=read();s=read();t=read();
    for(int i=1;i<=n;++i) f[i].head=-1;
    for(int i=1;i<=m;++i){
        int x,y,w;x=read();y=read();w=read();
        add(x,y,w);add(y,x,0);
    }
    dinic();
    printf("%lld",ans);
    return 0;
}
https://www.luogu.org/problem/show?pid=3376
原文地址:https://www.cnblogs.com/hanyu20021030/p/6602071.html