zoukankan      html  css  js  c++  java
  • 二分图匹配

    二分图匹配

    首先还是要了解二分图匹配是个什么东西

    ​ 分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

    ​ (以上来自百度百科)说简单一些就是对于一个无向图可以将它分为两个集合,对于同一集合内的元素一定没有边相连,而不同集合内的元素存在边相连,这样的图称之为二分图。

    那么二分图匹配呢?

    ​ 给定一个二分图,寻找与一个边集的边能够满足任意两条边都不依附在同一个顶点,这样叫做二分图的一个匹配。

    ​ 说的更简单一些也就是让二分图两个集合内的点一个一个对应起来。

    ​ 通常做题时我们对于一个二分图需要求它的一个最大匹配。也就是尽可能让边集中边的数量尽可能的多,尽可能多的点能够匹配在一起。

    匈牙利算法

    ​ 求解一个二分图的最大匹配,比较简单也是常用的办法就是匈牙利算法。

    ​ 算法证明比较复杂,所以下面只介绍算法实现的流程。

    ​ 1.让第一个集合中的点去匹配

    ​ 2.如果匹配到的点没有配对,那么就暂时先和这个点匹配起来

    ​ 3.如果匹配到的点已经配对了,那么尝试让与匹配到的这个点匹配的点再去匹配,如果能匹配到,则当前点和匹配到的点就匹配到一起,否则就不能。

    ​ 4.依次再对集合中的下一个点进行这样的匹配操作。

    需要注意的是:每一轮操作中,一个点只能被匹配一次。

    例题

    luogu 2055假期的宿舍 (一道板子题就不多说了x

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    int read(){
        int a=0,f=0;char p=getchar();
        while(!isdigit(p)){f|=p=='-';p=getchar();}
        while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();}
        return f?-a:a;
    }
    void print(int x){
        if(x<0)putchar('-');x=-x;
        if(x>=10)print(x/10);
        putchar(x%10+'0');
    }
    int flag1[60],flag2[60];
    int n;
    vector<int> m[100];
    bool gx[100][100];
    bool vis[100];
    int bf[100];
    bool dfs(int x){
        for(int i=0;i<m[x].size();i++){
            int j=m[x][i];
            if(vis[j])continue;
            vis[j]=1;
            if(!bf[j]||dfs(bf[j])){
                bf[j]=x;
                return true;
            }
        }
        return false;
    }
    int main(){
        int t;
        t=read();
        while(t--){
            int cnt=0;
            memset(flag1,0,sizeof(flag1));
            memset(flag2,0,sizeof(flag2));
            memset(m,0,sizeof(m));
            memset(gx,0,sizeof(gx));
            memset(bf,0,sizeof(bf));
            n=read();
            for(int i=1;i<=n;i++)
                flag1[i]=read();//如果是1表示是在校学生
            for(int i=1;i<=n;i++){
                flag2[i]=read();//1表示这个在校学生要回家睡觉
                if(flag1[i]==0)flag2[i]=1;
            }
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    gx[i][j]=read();
                    if(gx[i][j]){
                        if(flag1[j])m[i].push_back(j);//如果j在学校有床
                    }
                    if(i==j&&flag1[i])m[i].push_back(j);
                    
                }
            }
            for(int i=1;i<=n;i++){
                if((!flag1[i])||(!flag2[i])){//不是在学生或者他不回家睡觉
                    memset(vis,0,sizeof(vis));
                    if(!dfs(i))cnt++;
                }
            }
            if(cnt)cout<<"T_T"<<endl;
            else cout<<"^_^"<<endl;
        }
    }
    
  • 相关阅读:
    面试题
    学习Javascript闭包(Closure)
    git命令
    css3 3d翻转效果
    meta 如何写
    Java String equals和==的比较
    MySQL Explain详解
    MySQL explain,type分析(转)
    python的内存分析和处理
    python lambda的使用
  • 原文地址:https://www.cnblogs.com/huixinxinw/p/12725519.html
Copyright © 2011-2022 走看看