网络流初步

紫书上的代码,加了注释(EK算法)

#define INF 0x3f3f3f3f
#define mod 1000000007
const int maxn = 100 + 5;
using namespace std;
int n,m;
struct Edge{
    int from, to, cap, flow;
    Edge(int f, int t, int c, int fl):from(f),to(t),cap(c),flow(fl){}
};
struct EK{
    int n,m;
    vector<Edge> edges;
    vector<int> G[maxn];//每个结点i连接的结点j 即在edges中的下标
    int a[maxn];//当起点到i的可改进量
    int pre[maxn];
    void init(int n){
        for(int i=0; i<n; i++) G[i].clear();
        edges.clear();
    }
    void addedge(int from, int to, int cap){
        edges.push_back(Edge(from,to,cap,0));
        edges.push_back(Edge(to,from,0,0));
        m = (int)edges.size();
        G[from].push_back(m-2);//连接的边的序号 从0开始
        G[to].push_back(m-1);
    }
    int Maxflow(int s, int t){
        int flow = 0;
        for(;;){//有正反边一起跑 所以0的时候就不会再跑了
            memset(a, 0, sizeof(a));
            queue<int> q;
            q.push(s);//从起点开始
            a[s] = INF;
            while(!q.empty()){
                int u = q.front();
                q.pop();
                for(int i=0; i<G[u].size(); i++){//所有和该点连着的边的序号
                    Edge &e = edges[G[u][i]];
                    if(!a[e.to] && e.cap > e.flow){
                        pre[e.to] = G[u][i];//前驱 用来往前回溯更新流量
                        a[e.to] = min(a[u], e.cap - e.flow);//往后递推直到终点
                        q.push(e.to);
                    }
                }
                if(a[t]) break;//找到了一条增广路
            }
            if(!a[t]) break;//如果最小残量已经为0了就没有增广路了
            for(int i=t; i!=s; i=edges[pre[i]].from){
                edges[pre[i]].flow += a[t];
                edges[pre[i]^1].flow -= a[t];
            }
            flow += a[t];
        }
        return flow;
    }
};

dinic算法(邻接表)(结合POJ1273)

#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#define LL long long
#define INF 0x3f3f3f3f
#define mod 1000000007
const int maxn = 2000 + 5;
using namespace std;
int dis[250];//距源点距离,分层图
int n,m;//n点数,M边数
struct Edge{
    int from,to,cap;
    Edge(){}
    Edge(int f, int t, int c):from(f),to(t),cap(c){}
};
vector<Edge> edges;
vector<int> G[maxn];//存储相连的边的序号
void addedge(int u, int v, int cap)
{
    edges.push_back(Edge(u,v,cap));
    edges.push_back(Edge(v,u,0));
    int sz = (int)edges.size();
    G[u].push_back(sz-2);
    G[v].push_back(sz-1);
}
int bfs(int s, int t){//起点到终点
    queue<int> q;
    memset(dis, -1, sizeof(dis));
    dis[s] = 0;
    q.push(s);
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i=0; i<(int)G[u].size(); i++){
            Edge &e = edges[G[u][i]];
            if(dis[e.to] == -1 && e.cap > 0){
                dis[e.to] = dis[u] + 1;
                q.push(e.to);
            }
        }
    }
    if(dis[t] > 0) return 1;
    return 0;
}
int dinic(int x, int t, int flow){
    if(x == t) return flow;
    int a = 0;
    for(int i=0; i<(int)G[x].size(); i++){
        Edge &e = edges[G[x][i]];
        if(dis[e.to] == dis[x] + 1 && e.cap > 0 && (a = dinic(e.to,t,min(flow,e.cap)))){
            e.cap -= a;
            edges[G[x][i]^1].cap += a;
            return a;
        }
    }
    return 0;
}
int main(){
    while(scanf("%d%d",&m,&n) == 2){
        for(int i=0; i<maxn; i++) G[i].clear();
        edges.clear();
        for(int i=0; i<m; i++){
            int u,v,c;
            scanf("%d%d%d",&u,&v,&c);
            addedge(u, v, c);
            addedge(v, u, 0);
        }
        int ans = 0;
        while(bfs(1,n)){
            ans += dinic(1,n,INF);
        }
        printf("%d\n",ans);
    }
    return 0;
}

最小割最大流定理:

参考:这篇博客

在不存在增广路的残量网络中,当BFS找不到(s,t)时,把已标号的点看作S,其他的即为T,则(S,T)即是最小割

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值