最大流EK和Dinic算法

EK算法

最朴素的求最大流的算法。
做法:不停的寻找增广路,直到找不到为止

代码如下:

@Frosero
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#define INF 0x3f3f3f3f

using namespace std;
int n,m;
int cap[202][202],flow[202][202],mf[202],pre[202];
    //cap为网络的容量 flow为现在的流量 
    //mf[i]为原点到点i的最大流量 pre[i]为增广路上i点上一个点

int EK(int s,int t){
    memset(flow,0,sizeof(flow));
    queue<int>q;
    int ans = 0;
    while(1){
        while(!q.empty()) q.pop(); q.push(s);
        memset(mf,0,sizeof(mf));
        mf[1] = INF;
        while(!q.empty()){
            int u = q.front(); q.pop();
            for(int i=1;i<=m;i++)if(!mf[i] && flow[u][i] < cap[u][i]){
                pre[i] = u;
                q.push(i);
                mf[i] = min(mf[u],cap[u][i] - flow[u][i]);
            }
        }
        if(mf[t] == 0) break;
        ans += mf[t];
        for(int i=t;i!=s;i=pre[i]){
            flow[pre[i]][i] += mf[t];
            flow[i][pre[i]] -= mf[t];
        }
    }
    return ans;
}

int main(){
    while(scanf("%d %d",&n,&m)!=EOF){
        memset(cap,0,sizeof(cap));
        memset(flow,0,sizeof(flow));
        int u,v,w;
        while(n--){
            scanf("%d %d %d",&u,&v,&w);
            cap[u][v] += w;
        }
        printf("%d\n",EK(1,m));
    }
}

Dinic算法

Dinic的优化部分就是给残留网络生成一个层次图,然后尽量的利用层次图后再形成新的层次图。

理论上Dinic和EK算法的时间复杂度差不多,但是事实上Dinic算法要好得多。

代码如下:

@Frosero
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#define INF 0x3f3f3f3f

using namespace std;

int n,m,flow[202][202],cap[202][202];
int dis[202];
    //flow为现在的流量 cap为网络的容量
    //dis为点的层次

bool bfs(){                 //形成层次图
    memset(dis,-1,sizeof(dis));
    dis[1] = 0;
    queue<int>q; q.push(1);
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=1;i<=m;i++)if(dis[i] == -1 && flow[u][i] < cap[u][i]){
            dis[i] = dis[u] + 1;
            q.push(i);
        }
    }
    if(dis[m] == -1) return false;
    else return true;
}

int dfs(int s = 1,int f = INF){     //利用层次图不断寻找增广路
    if(s == m || f == 0) return f;
    int ans = 0;
    for(int i=1;i<=m;i++)if(dis[i] == dis[s] + 1){
        int a = dfs(i,min(f,cap[s][i] - flow[s][i]));
        if(a == 0) continue;
        flow[s][i] += a;
        flow[i][s] -= a;
        ans += a;
        f -= a;
        if(f <= 0) break;
    }
    return ans;
}


int dinic(){                //Dinic主过程
    int ans = 0;
    while(bfs()){
        ans += dfs();
    }
    return ans;
}


int main(){
    while(scanf("%d %d",&n,&m)!=EOF){   //本代码假设1为原点 m为汇点
        memset(flow,0,sizeof(flow));
        memset(cap,0,sizeof(cap));
        int u,v,w;
        while(n--){
            scanf("%d %d %d",&u,&v,&w);
            cap[u][v] += w;
        }
        printf("%d\n",dinic());
    }
    return 0;
}