二分图·(染色法+匈牙利)

文章讲述了如何通过染色法判断一棵无奇数环的树是否为二分图,以及如何使用匈牙利算法解决二分图中男生和女生的最大完美匹配问题,给出了相应的代码示例。
摘要由CSDN通过智能技术生成

 什么是二分图?二分图就是所有的点可以呗分为俩个集合,且集合内部的点互相之间没有边。

如果有一棵树,如果这颗树里面没有奇数环,那么这颗树就可以被划分为一个二分图。如何判断一颗树是否为一个二分图,一般会用到染色法。

染色法即通过dfs的方式,将一个点染色为1或则2,然而1所连接的边必须式2,不能是1,同理,2能连接的边也必须是1。代码如下

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m;
const int N=3e5+10;
int e[N],ne[N],idx;
int h[N];
int co[N];
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
bool dfs(int u,int x){//判断是否能染色成功
    co[u]=x;//将u染成x
    for(int i=h[u];i!=-1;i=ne[i]){
        int v=e[i];
        if(co[v]){//如果v的颜色确定
            if(co[v]==x)return false;//如果v,u的颜色相同,不能成功
        }
        else {//v的颜色未确定
            if(!dfs(v,3-x))return false;//判断v 染成3-x是否成功,如果失败返回false
        }
    }
    return true;
}
int main(){
    cin>>n>>m;
    memset(h,-1,sizeof h);
    for(int i=1;i<=m;i++){//存边
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
   for(int i=1;i<=n;i++){
       if(!co[i]){//考虑到存可能在不相连的
           if(dfs(i,1))continue;
           else {cout<<"No\n";return 0;}
       }
       
   }
   cout<<"Yes\n";
    return 0;
}

那么匈牙利算法又和这个二分有什么关系捏?

匈牙利算法,又称km算法,时间复杂度未n^3,匈牙利的算法是可以解决二分图的最大完美匹配的问题。就比如有俩个集合,一边是男的一边是女的,男的有n1个,女的有n2个,如果双发之间有好感度就有可能在一起,当然假设男女的性取向都很正确,所以不存在男男,女女的情况,而我们要求的就是男女能匹配到一起的最大匹配数量。

那么我们该如何实现捏?这里的话假设我们从男方角度出发,如果男有与女生有好感度,那么我们就可以记录女生所匹配的,如果这个女生已经有匹配的了,那么我们试试嫩否让这个女生匹配的男的换一个女朋友然后再占为己有。

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
typedef double D;
const int N =1e6+10;
typedef pair<int,int>Pii;
LL a[N];
int e[N],h[N],ne[N],idx;
int st[510];
int match[N];
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
bool dfs(int u){
    for(int i=h[u];i!=-1;i=ne[i]){
        int v=e[i];//预选的人之一
        if(st[v])continue;
        st[v]=1;//表示这个已经尝试匹配过了,不用再尝试
        if(!match[v]||dfs(match[v])){//如果这个人没有匹配成功,或者她的匹配对象还能再找一个,那么就可以匹配成
            match[v]=u;
            return true;
        }
        
    }
    return false;//如果所有预选的对象都不能成功,那么就返回false
}

void solved(){
    int n,m,e;
    cin>>n>>m>>e;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);//单向边
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        if(dfs(i))ans++;//匹配成功,答案加1
        memset(st,0,sizeof st);//清空数组
    }
    cout<<ans<<"\n";
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int tt;
    tt=1;
    while(tt--){
        solved();
    }
 
}

完结撒花!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值