二分图的匹配

本文介绍了二分图的判定及其最大匹配的概念,包括增广路算法和匈牙利算法,探讨了最大匹配的性质和求解方法,重点阐述了二分图带权最大匹配的KM算法,包括交错树、顶标和相等子图的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、二分图的判定:
   如果一张图的N个节点可以分成A,B两个非空集合,其中A∩B=空集,并且在同一集合内的点之间都没有边相连,那么称这张无向图为一张二分图。A,B分别称为二分图的左部和右部。
   定理: 一张无向图是二分图,当且仅当图中不存在奇环(长度为奇数的环)。
   
   根据该定理,我们可以用染色法进行二分图的判定。大致思想为:尝试用黑白两种颜色标记图中的节点,当一个节点被标记后,它的所有相邻节点应该被标记与它相反的颜色。若标记过程中有冲突,则说明图中存在奇环。二分图染色一般基于深度优先遍历实现,时间复杂度为O(N±M)。

   hihoCoder1121 二分图的判定:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<string>
#include<cmath>
#define ll long long
using namespace std;
const int maxn=40010;
const int _max=10010;
int head[_max], ver[maxn*2],nt[maxn*2];
int tot;
int ha[_max];
void add(int x,int y)
{
   
   
    ver[++tot]=y;nt[tot]=head[x];head[x]=tot;
}

bool dfs(int x,int cnt)
{
   
   
    ha[x]=cnt;
    for(int i=head[x];i;i=nt[i])
    {
   
   
        int y=ver[i];
        if(ha[y]==cnt) return false;
        else if(ha[y]==0&&dfs(y,-cnt)==false) return false;
    }
    return true;
}

int main(void)
{
   
   
    int t;
    scanf("%d",&t);
    while(t--)
    {
   
   
        int n,m;
        scanf("%d%d",&n,&m);
        memset(head,0,sizeof(head));
        memset(ha,0,sizeof(ha));
        tot=0;
        int x,y;
        for(int i=1;i<=m;i++)
        {
   
   
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        bool flag=true;
        for(int i=1;i<=n;i++)
        {
   
   
            if(ha[i]==0)
                if(dfs(i,1)==false)
            {
   
   
                flag=false;
                break;
            }
        }
        if(flag) printf("Correct\n");
        else printf("Wrong\n");
    }
    return 0;
}

二、二分图最大匹配:
   
   任意两条边都没有公共端点 的边的集合被称为图的一组匹配。在二分图中,包含边数最多的一组匹配被称为二分图的最大匹配。
   
   对于任意一组匹配S(S是一个边集),属于S的边被称为匹配边,不属于S的边被称为非匹配边。
   匹配边的端点被称为匹配点,其他节点被称为非匹配点。
   如果在二分图中存在一条连接两个非匹配点的路径path,使得非匹配边与匹配边在path上交替出现,那么称path是匹配S的增广路,也称交错路。
   
   增广路显然具有以下性质:
   (1) 长度len是奇数。
   (2)路径上第1,3,5……len条边是非匹配边,第2,4,6,……len-1条边是匹配边。

   正因为以上性质,如果我们把路径上所有边的状态取反,原来的匹配边变成非匹配的,原来的非匹配边变成匹配的,那么得到的新边集SS仍然是一组匹配,并且匹配边数增加了1。进一步可以得到推论:
   二分图的一组匹配S是最大匹配,当且仅当图中不存在S的增广路。

   
   匈牙利算法(增广路算法):
   匈牙利算法,又称增广路算法,用于计算二分图的最大匹配。它的主要过程为:
   (1)设S为空集,即所有边都是非匹配边。
   (2)寻找增广路path,把路径上所有边的匹配状态取反,得到一个更大的匹配SS。
   (3)重复第二步,直至图中不存在增广路。

   该算法的关键在于如何找到一条增广路。匈牙利算法依次尝试给每一个左部节点x寻找一个匹配的右部节点y。右部点y能与左部点x匹配,需要满足以下两个条件之一:
(1)y本身就是非匹配点。
此时无向边(x,y)本身就是非匹配边,自己构成一条长度为1的增广路。
(2)y已经与左部点xx匹配,但是从xx出发能找到另一个右部点yy与之匹配。
此时路径x–y--xx–yy为一条增广路。

   
在实际的程序实现中,我们采用深度优先搜索的框架,递归地从x出发寻找增广路。若找到,则在深搜回溯时,正好把路径上的匹配状态取反。另外,可以用全局bool数组标记节点的访问情况,避免重复搜索。
在这里插入图片描述
   
   
   匈牙利算法的正确性基于贪心策略,它的一个重要特点时:当一个节点称为匹配点后,至多因为找到增广路而更换匹配对象,但是绝对不会再变回非匹配点。
   对于每个左部节点,寻找增广路最多遍历整张二分图一次。因此,该算法的时间复杂度为O(NM)。

bool dfs(int x)
{
   
   
    for(int i=head[x],y;i;i=nt[i])
    {
   
   
        if(!visit[y=ver[i]])
        {
   
   
            visit[y]=1;
            if(!match[y]||dfs(match[y]))
            {
   
   
                match[y]=x;
                return true;
            }
        }
    }
    return false;
}

for(int i=1;i<=n;i++)
{
   
   
    memset(visit
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值