zoukankan      html  css  js  c++  java
  • 二分图与网络流 带权二分图的最大匹配

    二分图与网络流  带权二分图的最大匹配

    在某书上偶然发现,二分图和网络流是有联系的,在子图u中建立超级源点,在子图v中建立超级汇点,源点到u和汇点到v的每条边容量设为1,u和v中的边的容量也设为1,求出最大流也就是原二分图的最大匹配了。

    而求带权二分图的最大匹配也就很容易了,将u和v的权值设为容量,仍然建立超级源点和超级汇点转为网络流解决即可。

    真是一切皆可网络流啊。。。

    然而。。。

    下面是xdoj1048,二分图模版测试题,匈牙利算法649ms,Hotcroft_Carp算法155ms,而转为网络流用Edmonds_Karp算法超时。。看来网络流还没学到更高级的算法之前还是不要随便将二分图的题目转为网络流了,如果是带权最大匹配就可以尝试下。

    http://acm.xidian.edu.cn/problem.php?id=1048

    匈牙利算法:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #include<string>
    #include<math.h>
    #include<cctype>
     
    using namespace std;
     
    typedef long long ll;
    const int maxn=1000100;
    const int INF=(1<<29);
    const double EPS=0.0000000001;
    const double Pi=acos(-1.0);
     
    int uN,vN;
    vector<int> G[maxn];
    int link[maxn];
    bool vis[maxn];
    int m;
     
    bool dfs(int u)
    {
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!vis[v]){
                vis[v]=1;
                if(link[v]==-1||dfs(link[v])){
                    link[v]=u;
                    return true;
                }
            }
        }
        return false;
    }
     
    int hungary()
    {
        int res=0;
        memset(link,-1,sizeof(link));
        for(int u=0;u<uN;u++){
            memset(vis,0,sizeof(vis));
            if(dfs(u)) res++;
        }
        return res;
    }
     
    int main()
    {
        while(cin>>uN>>vN){
            for(int i=0;i<uN;i++) G[i].clear();
            cin>>m;
            while(m--){
                int u,v;
                cin>>u>>v;
                G[u].push_back(v);
            }
            cout<<hungary()<<endl;
        }
        return 0;
    }
     
    View Code

    Hotcroft_Carp算法:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #include<string>
    #include<math.h>
    #include<cctype>
     
    using namespace std;
     
    typedef long long ll;
    const int maxn=3100;
    const int INF=(1<<29);
    const double EPS=0.0000000001;
    const double Pi=acos(-1.0);
     
    int m;
    vector<int> G[maxn];
    int Mx[maxn],My[maxn],Nx,Ny;
    int dx[maxn],dy[maxn],dis;
    bool vis[maxn];
     
    bool searchP()
    {
        queue<int> q;
        dis=INF;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        for(int i=0;i<Nx;i++){
            if(Mx[i]==-1){
                q.push(i);
                dx[i]=0;
            }
        }
        while(!q.empty()){
            int u=q.front();
            q.pop();
            if(dx[u]>dis) break;
            for(int i=0;i<G[u].size();i++){
                int v=G[u][i];
                if(dy[v]==-1){
                    dy[v]=dx[u]+1;
                    if(My[v]==-1) dis=dy[v];
                    else{
                        dx[My[v]]=dy[v]+1;
                        q.push(My[v]);
                    }
                }
            }
        }
        return dis!=INF;
    }
     
    bool dfs(int u)
    {
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(!vis[v]&&dy[v]==dx[u]+1){
                vis[v]=1;
                if(My[v]!=-1&&dy[v]==dis) continue;
                if(My[v]==-1||dfs(My[v])){
                    My[v]=u;
                    Mx[u]=v;
                    return true;
                }
            }
        }
        return false;
    }
     
    int MaxMatch()
    {
        int res=0;
        memset(Mx,-1,sizeof(Mx));
        memset(My,-1,sizeof(My));
        while(searchP()){
            memset(vis,0,sizeof(vis));
            for(int i=0;i<Nx;i++){
                if(Mx[i]==-1&&dfs(i)) res++;
            }
        }
        return res;
    }
     
    int main()
    {
        while(cin>>Nx>>Ny){
            cin>>m;
            for(int i=0;i<Nx;i++) G[i].clear();
            memset(G,0,sizeof(G));
            while(m--){
                int u,v;
                scanf("%d%d",&u,&v);
                G[u].push_back(v);
            }
            cout<<MaxMatch()<<endl;
        }
        return 0;
    }
    View Code

    转为网络流超时的Edmonds_Karp算法:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #include<string>
    #include<math.h>
    #include<cctype>
     
    using namespace std;
     
    typedef long long ll;
    const int maxn=1200;
    const int INF=(1<<29);
    const double EPS=0.0000000001;
    const double Pi=acos(-1.0);
     
    int uN,vN;
    int m;
    int cap[maxn][maxn],flow[maxn][maxn];
    int s,t;
     
    int Edmonds_Karp(int s,int t)
    {
        int f=0;
        int p[maxn],a[maxn];
        queue<int> q;
        memset(flow,0,sizeof(flow));
        while(1){
            memset(a,0,sizeof(a));
            a[s]=INF;
            q.push(s);
            while(!q.empty()){
                int u=q.front();q.pop();
                for(int v=0;v<=t;v++){
                    if(!a[v]&&cap[u][v]-flow[u][v]>0){
                        q.push(v);
                        p[v]=u;
                        a[v]=min(a[u],cap[u][v]-flow[u][v]);
                    }
                }
            }
            if(a[t]==0) return f;
            for(int u=t;u!=s;u=p[u]){
                flow[p[u]][u]+=a[t];
                flow[u][p[u]]-=a[t];
            }
            f+=a[t];
        }
    }
     
    int main()
    {
        while(cin>>uN>>vN){
            s=uN+vN;
            t=s+1;
            cin>>m;
            memset(cap,0,sizeof(cap));
            while(m--){
                int u,v;
                scanf("%d%d",&u,&v);
                v+=uN;
                cap[u][v]=1;
            }
            for(int u=0;u<uN;u++) cap[s][u]=1;
            for(int v=uN;v<uN+vN;v++) cap[v][t]=1;
            cout<<Edmonds_Karp(s,t)<<endl;
        }
        return 0;
    }
     
    View Code
    没有AC不了的题,只有不努力的ACMER!
  • 相关阅读:
    bzoj3994:[SDOI2015]约数个数和
    数列分块1-9
    luogu P2059 [JLOI2013]卡牌游戏
    luogu P1623 [CEOI2007]树的匹配Treasury
    博弈论与SG函数
    luogu P1169 [ZJOI2007]棋盘制作
    luogu P1623 [CEOI2007]树的匹配Treasury
    [BZOJ4896][THUSC2016]补退选(Trie)
    [BZOJ3745][COCI2015]Norma(分治)
    [BZOJ5006][LOJ#2290][THUWC2017]随机二分图(概率+状压DP)
  • 原文地址:https://www.cnblogs.com/--560/p/4550578.html
Copyright © 2011-2022 走看看