增广路算法入门

增广路定理:
我们用未覆盖点来表示不与任何匹配边邻接的点,其他点为匹配点,即恰好和一条匹配边邻接的点。从未覆盖点出发,依次经过非匹配边,匹配边,非匹配边,匹配边…所得的路称为交替路。如果交替路的终点是一个未覆盖点,则称这条交替路为一条增广路,非匹配边比匹配边多一条。

增广路的作用是改进匹配,假设我们已经找到一个匹配,如何判断他 是否是最大匹配?看增广路,如果有一条增广路,呢么把此路上的匹配边和非匹配边互换,得到的匹配边比刚才多一条。反之,若找不到增广路,则当前为最大匹配

一个匹配是最大匹配的充要条件是不存在增广路,这个充要条件适用于任意图。

增广路算法:
根据增广路定理,最大匹配可以通过反复寻找增广路来求解,如何找到答案?根据定义首先找到一个未覆盖的点u作为起点,设这个u是X的结点。接下来需要选一个从u出发的非匹配边(u,v),达到Y结点v。如果v是未覆盖点。说明我们成功找到了一条增广路,如果v是匹配点,那我们下一不得走匹配边,因为一个匹配点恰好与一个匹配边邻接。设匹配点v邻接的匹配边的另一端点left[v],呢么可以理解从u直接走到了left[v],而这个left[v]也是一个X结点。如果始终没有找到覆盖点,最后会扩展出一颗匈牙利树。

这样,我们得到了一个算法,即每次选一个未覆盖点u进行DFS,注意,如果找不到u开头的增广路,则换一个未覆盖点进行DFS,且以后再也不从u出发找增广路。换句话说,如果以后存在一个从出发的增广路,呢么现在就找得到。
代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=600+5;
bool line[maxn][maxn];
//line[x][y]=true表示x号女生喜欢y男生(边)
int boy[maxn];
//存储y号男生匹配边另一端的匹配点女生,如果是未覆盖点则为0
bool use[maxn];
//存储y号男生是否在这条交替路上被使用过,男生是否被别人喜欢
int k,n,m;
bool dfs(int x)
{

    for(int j=1;j<=m;j++)
    {
        if(line[x][j]&&!use[j])
           {
               use[j]=true;
               if(!boy[j]||dfs(boy[j]))
               {
                   //满足上面的判断语句说明找到了增广路
                   //即终点是未覆盖点的交替路
                   boy[j]=x;
                   return true;

               }
           }
        //该条路不是增广路
    }

    return false;

}

int main()
{
    while(cin>>k)
    {
        if(!k)
            break;
        cin>>n>>m;
        int x,y;
        int ans=0;
        memset(line,false,sizeof(line));
        memset(boy,0,sizeof(boy));
        while(k--)
        {
            cin>>x>>y;
            line[x][y]=true;
        }
        for(int i=1;i<=n;i++)
        {
            memset(use,false,sizeof(use));
            if(dfs(i))
                ans++;
        }
        cout<<ans<<endl;
    }

    return 0;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值