最大匹配问题(匈牙利算法)

匈牙利算法(简单总结)

结束简单图论算法,撒花(哈哈哈)

  • 啥是匈牙利算法
    就是二分图求最大匹配
    1 将所有点分为两个阵营(阵营里没有连线,只能和对方阵营连线)
    2 求最大的一一对映数是多少

  • 来个通俗版本

    现在有 编号1,2,3,4个男同胞和1,2,3,4个女同胞
    他们之间有互相暗恋的对象(有的还喜欢好几个)
    我们就是月老进行红线牵,来能牵出多少对(保证一男一女)

这时匈牙利算法就可以当作月老专用算法
1 先选一个阵营
2 进行连线,如果有人,这看他的伴侣,能不能换一个成立,就换
3 以此类推 , 得最大匹配数
模板
一定不要背,理解就可以打出来,不需要硬背,我反正都是理解记忆

int n1, n2;     // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N], e[M], ne[M], idx;     // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N];       // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N];     // 表示第二个集合中的每个点是否已经被遍历过

bool find(int x)
{
    for (int i = h[x]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!st[j])
        {
            st[j] = true;
            if (match[j] == 0 || find(match[j]))
            {
                match[j] = x;
                return true;
            }
        }
    }

    return false;
}

// 求最大匹配数,依次枚举第一个集合中的每个点能否匹配第二个集合中的点
int res = 0;
for (int i = 1; i <= n1; i ++ )
{
    memset(st, false, sizeof st);
    if (find(i)) res ++ ;
}

肯定很抽象,没关系(代码很简单)
hdu一道月老题(模板题),看看吧,哈哈
->过山车
代码

#include<iostream>
#include<cstring>
using namespace std;
const int N=510;
int n,m,k;
int h[N],e[N*2],ne[N*2],idx;
bool st[N];
int cut[N];
void add(int a,int b){
    e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
bool find(int x){
    for(int i=h[x];~i;i=ne[i]){
        int j=e[i];
        if(!st[j]){
            st[j]=true;
            if(!cut[j]||find(cut[j])){
                cut[j]=x;
                return true;
            }
        }
    }
    return false;
}
int main(){
    while(cin>>k,k){
        cin>>n>>m;
        memset(h,-1,sizeof h);idx=0;
        memset(cut,0,sizeof cut);
        for(;k;k--){
            int a,b;
            scanf("%d%d",&a,&b);
            add(a,b);
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            if(find(i)){
                ans++;
                memset(st,0,sizeof st);
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

还有一道模板题
P2071 座位安排
代码

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=8010;
int h[N],e[N*2],ne[N*2],idx;
int macth[N];
bool st[N];
int n;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool find(int x){
    for(int i=h[x];~i;i=ne[i]){
        int j=e[i];
        if(!st[j]){
            st[j]=true;
            if(!macth[j]||find(macth[j])){
                macth[j]=x;
                return true;
            }
        }
    }
    return false;
}
int main(){
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=1;i<=2*n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        add(i,a);
        add(i,a+n);
        add(i,b);
        add(i,b+n);
    }
    int ans=0;
    for(int i=1;i<=2*n;i++){
        memset(st,0,sizeof st);
        if(find(i)) ans++;
    }
    cout<<ans;
    return 0;
}

再来一道抽像的最大匹配问题

棋盘覆盖

代码

#include<iostream>
#include<algorithm>
#include<cstring>
#define x first
#define y second
using namespace std;
typedef pair<int,int>  PII;
const int N=110;
PII cut[N][N];
bool g[N][N];
bool st[N][N];
int n,m;
int fx[]={-1,0,1,0},fy[]={0,1,0,-1};
int find(int xx,int yy){
    for(int i=0;i<4;i++){
        int u=xx+fx[i],v=yy+fy[i];
        if(!st[u][v]&&!g[u][v]&&u&&v&&v<=n&&u<=n){
            st[u][v]=true;
            if(!cut[u][v].x||find(cut[u][v].x,cut[u][v].y)){
                cut[u][v]={xx,yy};
                return true;
            }
        }
    }
    return false;
}
int main(){
    cin>>n>>m;
    for(;m;m--){
        int a,b;
        scanf("%d%d",&a,&b);
        g[a][b]=true;
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if((i+j)&1&&!g[i][j]){
                if(find(i,j)) ans++;
                memset(st,0,sizeof st);
            }
    cout<<ans;
    return 0;
}

详细解析可以看链接的题解,我比较懒

还有一道简单的棋盘问题
車的放置

代码

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;
const int N=210;
bool g[N][N];
bool st[N];
int cut[N];
int n,m,t;
bool find(int u){
    for(int i=1;i<=m;i++){
        if(!st[i]&&!g[u][i]){
            st[i]=true;
            if(!cut[i]||find(cut[i])){
                cut[i]=u;
                return true;
            }
        }
    }
    return false;
}
int main(){
    cin>>n>>m>>t;
    for(;t;t--){
        int x,y;
        scanf("%d%d",&x,&y);
        g[x][y]=true;
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        memset(st,0,sizeof st);
        if(find(i)) ans++;
    }
    cout<<ans;
    return 0;
}

就这么多吧,最大匹配问题模板不会难,在于怎么转换问题
qwq萌新,举手敬礼
在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值