二分图 学习笔记

前言:寒假讲过了二分图,但没有学会。现在趁着图论复习再学一遍。

------------------

定义:通俗点来讲,如果给你一张图,能将其分为两个点集且点集内部没有连边,那么此图为二分图。

关于二分图有一个性质:二分图一定不存在奇环。证明过程如下:

二分图 学习笔记

二分图 学习笔记

二分图的判定:我们采用染色法。

bfs图,假设把1个点标记成1,那么与它相邻的点都标记成0。如果相邻的点已经被标记过,那么看颜色是否相同。如果相同那么返回$false$。

注意图可能不是联通的,所以我们要$n$个点都找一遍。

bool check(int x)
{
    queue<int> q;
    q.push(x);color[now]=1;
    while(!q.empty())
    {
        int now=q.front();q.pop();
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (color[to]==-1) color[to]=1^color[now];
            else if (color[to]==color[now]) return false;
        }
    }
    return true;
} 
memset(color,-1,sizeof(color));
for (int i=1;i<=n;i++) if (color[i]==-1) flag=check(i);

另一种写法,利用搜索树:

bool dfs(int now)
{
    for (int i=0;i<v[now].size();i++)
    {
        int to=v[now][i];
        if (!dep[to]) dep[to]=dep[now]+1;
        else{
            if ((dep[to]-dep[now])%2==0) return false;
        }
    }
    return true;
}

 匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
极大匹配(Maximal Matching)是指在当前已完成的匹配下,无法再通过增加未完成匹配的边的方式来增加匹配的边数。最大匹配(maximum matching)是所有极大匹配当中边数最大的一个匹配。选择这样的边数最大的子集称为图的最大匹配问题。
如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。

求二分图的最大匹配可以用网络流匈牙利算法。这里主要讲匈牙利算法的实现。

匈牙利算法核心是找增广路。增广路:若P是图G中一条连通两个未匹配顶点的路径,并且属于M的边和不属于M的边(即已匹配和待匹配的边)在P上交替出现,则称P为相对于M的一条增广路径。

总体来说步骤有三步:

1.后来的和先来的发生冲突,先来的退让。

2.如果先来的没地方没有其他匹配点,那么后来的寻找其他点。

如果后来的没有匹配点,返回$false$。

$dfs$实现:

bool dfs(int x)
{
    for (int y=1;y<=m;y++)
    {
        if (flag[x][y]&&!vis[y])
        {
            vis[y]=1;
            if (cy[y]==-1||dfs(cy[y]))
            {
                cx[x]=y;
                cy[y]=x;
                return true;
            }
        }
    }
    return false;
}

洛谷P3386 【模板】二分图最大匹配

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int cx[505],cy[505];
int vis[1005];
bool flag[505][505];
int n,m,e,ans;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
bool dfs(int x)
{
    for (int y=1;y<=m;y++)
    {
        if (flag[x][y]&&!vis[y])
        {
            vis[y]=1;
            if (cy[y]==-1||dfs(cy[y]))
            {
                cx[x]=y;
                cy[y]=x;
                return true;
            }
        }
    }
    return false;
}
signed main()
{
    n=read(),m=read(),e=read();
    for (int i=1;i<=e;i++)
    {
        int x=read(),y=read();
        if (x>=1&&y>=1&&x<=n&&y<=m)
            flag[x][y]=true;
    }
    memset(cx,-1,sizeof(cx));
    memset(cy,-1,sizeof(cy));
    for (int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        ans+=dfs(i);    
    } 
    printf("%d",ans);
    return 0;
}

定理:二分图的最小点覆盖等于二分图最大匹配。二分图最大边覆盖等于$n$减最大匹配。

二分图的最大独立集=顶点数-二分图最大匹配数=二分图最小边覆盖。

-----------------

后记:想要更详细的学习二分图可以去看这个,写得比较详细。毕竟我还是个蒟蒻QAQ。