二分图匹配复习——匈牙利和KM算法

99 篇文章 2 订阅

一,二分图最大匹配(匈牙利算法)

基本思想:没有机会,就创造机会

代码实现:

#include<bits/stdc++.h>
using namespace std;
const int N=500;
int mp[N][N];
int match[N],vis[N];
int k,m,n;  //k是连接数 m是左边个数 n是右边个数 
bool dfs(int x)
{
    for(int i=1; i<=n; i++)
    {
        if(mp[x][i]&&!vis[i]) //可以连接并且未连接过 
        {
            vis[i]=1;
            if(match[i]==0||dfs(match[i]))
            {
                match[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int x,y;
    while(scanf("%d",&k)&&k)
    {
        scanf("%d%d",&m,&n);
        memset(mp,0,sizeof(mp));
        memset(match,0,sizeof(vis));
        for(int i=0; i<k; i++)
        {
            scanf("%d%d",&x,&y);
            mp[x][y]=1;
        }
        int sum=0;
        for(int i=1; i<=m; i++)
        {
            memset(vis,0,sizeof(vis));
            if(dfs(i)) sum++;
        }
        printf("%d\n",sum);
    }
    return 0;
}

二,二分图最优匹配(KM算法)

基本思想:

(1) 初始化可行标杆 
(2) 用匈牙利算法寻找完备匹配 
(3) 若未找到完备匹配则修改可行标杆 

(4) 重复(2)(3)直到找到相等子图的完备匹配 

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int qwq=0x7fffffff;
int w[1000][1000];  //w数组记录边权值 
int line[1000],usex[1000],usey[1000],cx[1000],cy[1000];  //line数组记录右边端点所连的左端点, usex,usey数组记录是否曾访问过,也是判断是否在增广路上,cx,cy数组就是记录点的顶标 
int n,ans,m;  //n左m右 
bool find(int x){
    usex[x]=1;
    for (int i=1;i<=m;i++){
        if ((usey[i]==0)&&(cx[x]+cy[i]==w[x][i])){   //如果这个点未访问过并且它是子图里面的边 
            usey[i]=1;
            if ((line[i]==0)||find(line[i])){   //如果这个点未匹配或者匹配点能更改 
                line[i]=x;
                return true;
            }
        }
    }
    return false;
}
int km(){
    for (int i=1;i<=n;i++){  //分别对左边点依次匹配 
        while (true){
        int d=qwq;
        memset(usex,0,sizeof(usex));
        memset(usey,0,sizeof(usey));
        if (find(i)) break;  //直到成功匹配才换下一个点匹配 
        for (int j=1;j<=n;j++)
            if (usex[j])
             for (int k=1;k<=m;k++)
             if (!usey[k]) d=min(d,cx[j]+cy[k]-w[j][k]);  //计算d值 
        if (d==qwq) return -1;  
        for (int j=1;j<=n;j++)
         if (usex[j]) cx[j]-=d;   
        for (int j=1;j<=m;j++)
         if (usey[j]) cy[j]+=d;     //添加新边 
       }
    }
    ans=0;
    for (int i=1;i<=m;i++)
     ans+=w[line[i]][i];
    return ans;
}
int main(){
    while (~scanf("%d%d",&n,&m)){
    memset(cy,0,sizeof(cy));
    memset(w,0,sizeof(w));
    memset(cx,0,sizeof(cx));
    for (int i=1;i<=n;i++){
     int d=0;
     for (int j=1;j<=n;j++){
      scanf("%d",&w[i][j]);
      d=max(d,w[i][j]);   //此处顺便初始化左边点的顶标 
       }
    cx[i]=d;
    }
    memset(line,0,sizeof(line));
    printf("%d\n",km());
}
    return 0;
}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KM算法,全称Kuhn-Munkres算法,是一种用于求解二分图的最佳匹配的算法。它可以找到一个匹配,使得两个集合内的所有顶点能够一一匹配,并且获得的权值最大或最小。KM算法在求解带权二分图匹配时,融合了匈牙利算法的思想。算法的步骤如下: 1. 初始化:将两个集合内的顶点分别标记为未被匹配状态。 2. 根据特定的规则,遍历第一个集合内的顶点。 3. 对于每个选中的顶点,遍历第二个集合内的顶点,找到与其相连的较优边。较优边的选择可以根据具体情况而定,可以是较大的权值或者较小的权值。 4. 如果找到了满足条件的边,判断该边对应的第二个顶点是否已经被匹配。如果该顶点还未被匹配,则直接将其与第一个顶点进行匹配。 5. 如果该顶点已经被匹配,但是与其匹配的顶点还可以找到其他的可匹配顶点,则将该顶点重新匹配给第一个顶点。 6. 循环执行步骤2-5,直到无法找到满足条件的边。 通过这样的循环匹配KM算法能够找到二分图的最佳匹配。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [二分图的完全匹配---KM算法](https://blog.csdn.net/li13168690086/article/details/81557890)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值