首页 > 其他 > 详细

【网络流相关】二分图匹配

时间:2019-12-18 20:38:20      阅读:82      评论:0      收藏:0      [点我收藏+]

Luogu P3386
首先看看二分图的定义:

二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。——百度百科

举个例子:这样的一个图就是二分图。
技术分享图片


那么什么叫做二分图的匹配?
也就是在二分图中选择若干条边,其中任意两条边的端点不相同。此时边集元素的个数就是二分图的一个匹配。
那么很显然二分图的最大匹配就是边集个数最多的情况。
举个例子:
下面图中红色边构成了一个二分图匹配
技术分享图片

下面图中红色边不构成二分图匹配
技术分享图片

对于二分图最大匹配的问题,我们通常匈牙利算法或者网络最大流来解决。
我完全没有学过匈牙利算法,所以 本文着重于网络最大流。
不过其实没什么好分析的
如图所示:对二分图建立一个超级源点和一个超级汇点,源点向点集\(A\)连一条容量为\(1\)的边,点集\(B\)x向汇点连一条容量为\(1\)的边,然后跑一遍最大流即可。
技术分享图片

由于在二分图中\(Dinic\)算法的效率非常高,甚至高于匈牙利算法,所以我们通常使用\(Dinic\)跑二分图匹配

#include<cstdio>
#include<queue>
using namespace std;
int n,m,num,cnt,u,v,head[2005],cur[2005],dis[2005],ans;
bool vis[2005];
struct data
{
    int to,next,val;
}e[5000005];
void add(int u,int v,int val)
{
    e[++cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
    e[cnt].val=val;
}
bool bfs(int s,int t)
{
    queue<int> que;
    que.push(s);
    for (int i=1;i<=n+m+2;i++) dis[i]=0,vis[i]=false,cur[i]=head[i];
    vis[s]=true;
    dis[s]=1;
    while (!que.empty())
    {
        int now=que.front();
        que.pop();
        for (int i=head[now];i;i=e[i].next)
        {
            v=e[i].to;
            if (!vis[v]&&e[i].val>0)
            {
                dis[v]=dis[now]+1;
                vis[v]=true;
                if (v==t) return true;
                que.push(v);
            }
        }
    }
    return false;
}
int dfs(int now,int t,int flow)
{
    if (!flow||now==t) return flow;
    int used=0;
    for (int i=cur[now];i;i=e[i].next)
    {
        cur[now]=i;
        v=e[i].to;
        if (dis[now]+1!=dis[v]) continue;
        int tmp=dfs(v,t,min(flow-used,e[i].val));
        if (tmp)
        {
            e[i].val-=tmp;
            e[i^1].val+=tmp;
            used+=tmp;
            if (flow-used==0) return flow;
        }
    }
    return used;
}
void Dinic(int s,int t)
{
    while (bfs(s,t)) ans+=dfs(s,t,0x7fffffff);
}
int main()
{
    scanf("%d%d%d",&n,&m,&num);
    cnt=1;
    for (int i=1;i<=num;i++)
    {
        scanf("%d%d",&u,&v);
        if (u>n||v>m) continue;
        add(u,v+n,1);
        add(v+n,u,0);
    }
    for (int i=1;i<=n;i++) add(n+m+1,i,1),add(i,n+m+1,0);
    for (int i=n+1;i<=m+n;i++) add(i,n+m+2,1),add(n+m+2,i,0);
    Dinic(n+m+1,n+m+2);
    printf("%d",ans);
    return 0;
}

【网络流相关】二分图匹配

原文:https://www.cnblogs.com/notscience/p/12063388.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!