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

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

在某书上偶然发现,二分图和网络流是有联系的,在子图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

 

转载于:https://www.cnblogs.com/--560/p/4550578.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值