1. 程式人生 > >二分圖最大匹配 - 網路流

二分圖最大匹配 - 網路流

建立一個超級源點和超級匯點,點與點之間的容量均為1,因為一個點只能匹配一個點,源點向所有左邊的點連邊,匯點向右邊的點連邊。最後網路的最大流即為最大匹配。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 2005

struct queue {
    int q[MAXN],head,tail;
    void reset() {head = 1; tail = 0;}
    int front() {return q[head];}
    void push(int x) {q[++tail] = x;}
    void pop() {++head;}
    bool empty() {return head>tail;}
}q;

struct edge {
    int v,next,c;
}G[MAXN*MAXN<<1];

int d[MAXN],head[MAXN],cur[MAXN];
int N,M,E,S,T,tot = -1;

inline void add(int u,int v,int c) {
    G[++tot] = (edge) {v,head[u],c}; head[u] = tot;
}

inline bool bfs() {
    
    q.reset();
    std::memset(d,0,sizeof(d));

    d[S] = 1; q.push(S);
    while(!q.empty()) {
        int u = q.front(); q.pop();
        for(int i=head[u];i!=-1;i=G[i].next) {
            if(G[i].c<=0) continue;
            int v = G[i].v; if(d[v]!=0) continue;
            d[v] = d[u] + 1; q.push(v);
        }
    }
    return d[T] != 0;
}

int dfs(int u,int a) {
    if(u==T) return a;
    int flow = 0,temp;
    for(int& i=cur[u];i!=-1;i=G[i].next) {
        int v = G[i].v;
        if(d[v]!=d[u]+1) continue;
        if(G[i].c>0&&(temp = dfs(v,std::min(G[i].c,a)))) {
            G[i].c -= temp;
            G[i^1].c += temp;
            flow += temp;
            a -= temp;
            if(a==0) return flow;
        }
    }
    return flow;
}

inline int dinic() {
    int flow = 0;
    while(bfs()) {
        for(int i=1;i<=N+M+2;++i) cur[i] = head[i];
        flow += dfs(S,2147483647);
    }
    return flow;
}

int main() {

    scanf("%d%d%d",&N,&M,&E);
    std::memset(head,-1,sizeof(head));

    int u,v;
    for(int i=1;i<=E;++i) {
        scanf("%d%d",&u,&v);
        add(u,v+N,1); add(v+N,u,0);
    }
    S = N + M + 1; T = S + 1;
    for(int i=1;i<=N;++i) {
        add(S,i,1); add(i,S,0);
    }
    for(int i=N+1;i<=N+M;++i) {
        add(i,T,1); add(T,i,0);
    }

    printf("%d",dinic());
    return 0;
}