Dinic 二分图最大匹配最大流解法(来自lixiyi学姐的模板

来源:互联网 发布:一念之差网络大电影 编辑:程序博客网 时间:2024/05/29 08:00
/*    Dinic算法,复杂度O(V^2E)    总是寻找最短的增广路,并沿着它增广    实际运行速度快,可以用作模板 */const int inf = 2147483647;const double eps = 1e-8;const int maxn = 505;const ll mod = 1e9+7;struct edge{    int to, cap, rev;}; vector<edge> G[maxn];int level[maxn];        //各点所属层数 int iter[maxn];         //iter可以避免对没有用的边进行多次检查 void addedge(int from, int to, int cap){    G[from].push_back((edge){to, cap, (int)G[to].size()});    G[to].push_back((edge){from, 0, (int)G[from].size()-1});}//构造分层图 void bfs(int s){    memset(level, -1, sizeof(level));    queue<int> q;    level[s] = 0;    q.push(s);    while(!q.empty()){        int v = q.front(); q.pop();        for(int i=0; i<G[v].size(); i++){            edge &e = G[v][i];            if(e.cap>0 && level[e.to]<0){   //边容量大于0且还为给定层数                 level[e.to] = level[v]+1;                q.push(e.to);            }        }    }} //dfs寻找增广路 int dfs(int v, int t, int f){    if(v == t) return f;                            //已经到了终点t     for(int &i = iter[v]; i<G[v].size(); i++){      //i从iter[v]处开始检查,&:修改i时,iter也会修改         edge &e = G[v][i];        if(e.cap > 0 && level[v]<level[e.to]){      //可增广,且属于v的下一层             int d = dfs(e.to, t, min(f, e.cap));            if(d>0){                e.cap -= d;                G[e.to][e.rev].cap += d;                return d;             }        }    }    return 0;}int max_flow(int s, int t){    int flow = 0;    for( ;; ){        bfs(s);                         //构建分层图         if(level[t]<0) return flow;     //到终点的分层图已经造不出来了,即求出了最大流         memset(iter, 0, sizeof(iter));          int f;        while((f = dfs(s, t, inf))>0){            flow += f;        }    }}int main(){    int n, m;    scanf("%d%d", &n, &m);    //注意下标转成从0开始     for(int i=0; i<m; i++){        int u, v, cap;        scanf("%d%d%d", &u, &v, &cap);        addedge(--u, --v, cap);     }     int ans = max_flow(0, n-1);    printf("%d\n", ans);    return 0;} 
#include<iostream>#include<queue>#include<stack>#include<vector>#include<set>#include<math.h>#include<string.h>#include<stdlib.h>#include<stdio.h>#include<string>#include<map>#include<algorithm>#include<sstream>//#include<ctype.h>using namespace std;typedef long long ll;//typedef pair<int, int> P;/*    二分图最大匹配最大流简化做法,复杂度O(|V||E|)*/const int inf = 2147483647;const double eps = 1e-8;const int maxn = 505;const ll mod = 1e9+7;int n, k;vector<int> G[maxn];int match[maxn];        //匹配 bool used[maxn];void addedge(int u, int v){    G[u].push_back(v);    G[v].push_back(u);}//dfs寻找增广路 bool dfs(int v){    used[v] = true;    for(int i=0; i<G[v].size(); i++){        int u = G[v][i], w = match[u];        if(w<0 || !used[w] && dfs(w)){  //u未匹配过,或还有增广路             match[v] = u;            match[u] = v;            return true;        }    }    return false;}//求解二分图的最大匹配 int bipartite_matching(){    int res = 0;    memset(match, -1, sizeof(match));    for(int v = 0; v<n+k; v++){        if(match[v] < 0){            memset(used, 0, sizeof(used));            if(dfs(v)){                res++;            }        }    }     return res;}int main(){    while(scanf("%d%d", &n, &k) == 2){        for(int i=0; i<n+k; i++){            G[i].clear();        }         for(int i=0; i<n; i++){            int m;            scanf("%d", &m);            for(int j=0; j<m; j++){                int b;                scanf("%d", &b);                addedge(i, n+b-1);            }        }        printf("%d\n", bipartite_matching());    }    return 0;} input:5 52 2 53 2 3 42 1 53 1 2 51 2 n=5 m=55只奶牛 5个谷仓每只奶牛可以去那些谷仓数目 谷仓编号
原创粉丝点击