二分图判定&二分图最大匹配模板

二分图定义

二分图判定&二分图最大匹配模板_第1张图片
可以把所有的点划分成两个集合,集合内部不存在边,集合之间存在边;

01染色判定二分图

性质

  • 一个图是二分图等价于不存在奇数环

奇数环是指点的个数是奇数的环,如下图;

二分图判定&二分图最大匹配模板_第2张图片

有一个通俗的解释,奇数个点无法被两种颜色均分


那么我们的做法很简单,如果一个点没有被染色,那么我们将它(记为 u u u)染为白色,将与 u u u相连的点染成黑色;

不断重复这个过程即可,若过程中发现同色相连,那么就产生矛盾了;

染色法判二分图

传送门

题面

二分图判定&二分图最大匹配模板_第3张图片

时间复杂度

O ( N + M ) , N 为 点 的 个 数 , M 为 边 的 个 数 O(N+M),N为点的个数,M为边的个数 O(N+M),N,M

Code

#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;

const int N = 1e5 + 10;

int color[N];
vector<int> G[N];
int n,m;
bool dfs(int u,int c){
    color[u] = c;
    for(auto to : G[u]){
        if(color[to] != -1){
            if(color[to] == c) return false;
        }
        else{
            if(!dfs(to,c^1)) return false;
        }
    }
    return true;
}
void solve(){
    cin >> n >> m;
    while(m--){
        int u,v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for(int i=1;i<=n;++i) color[i] = -1;
    bool ff = 1;
    for(int i=1;i<=n;++i){
        if(color[i] == -1){
            ff = dfs(i,0);
            if(!ff) break;
        }
    }
    if(ff) cout << "Yes\n";
    else cout << "No\n";
}

signed main(){
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    solve();
    return 0;
}

匈牙利算法

用于求解二分图的最大的成功匹配;

成功匹配指的是,两个点一一配对,不存在脚踩多条船的情况;

也可以称为,月老算法

比如我们是月老,问我们最多能给多少对男女牵红线(一夫一妻!!!);

二分图判定&二分图最大匹配模板_第4张图片

算法过程是这样的,如果一个点可以匹配另一个点,那么我们直接匹配,皆大欢喜;

如果不能匹配,比如说 u u u的心仪对象是 v v v,但是 v v v已经和 w w w配对了;那么 u u u就会尝试把 w w w绿了,但是绿的前提是 w w w能找到另外的新欢,比如说 k k k

那么 u , v u,v u,v配对, w , k w,k w,k配对;

比如说下图的左三就绿了左一,抢了右二…(NTR)

二分图判定&二分图最大匹配模板_第5张图片

二分图的最大匹配

题面

传送门
二分图判定&二分图最大匹配模板_第6张图片

时间复杂度

O ( N ∗ M ) , N 为 点 数 , M 为 边 数 O(N*M),N为点数,M为边数 O(NM),N,M,实际时间没有这么大;

Code

注意一个地方,虽然二分图是无向图,但是我们这里存图只用存左边到右边,因为只用到了左边到右边;

#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;

const int N = 510 + 10;

int n1,n2,m;

vector<int> G[N];
bool st[N];//右边的每个点是否访问过
int match[N];//右边点匹配的点是谁
bool dfs(int u){
    for(auto to : G[u]){
        if(st[to]) continue;
        st[to] = 1;//右边每个点只考虑一次
        //如果没有匹配,或者匹配的人另寻新欢
        if(match[to] == 0 || dfs(match[to])){
            match[to] = u;
            return 1;
        }
    }
    return 0;
}
void solve(){
    cin >> n1 >> n2 >> m;
    while(m--){
        int u,v;
        cin >> u >> v;
        G[u].push_back(v);
    }
    //为左边每个点匹配
    int res = 0;
    for(int i=1;i<=n1;++i){
        memset(st,0,sizeof st);
        if(dfs(i)) ++res;
    }
    cout << res;
}

signed main(){
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    solve();
    return 0;
}

你可能感兴趣的:(图论,模板,算法,图论,动态规划)