染色法判定二分图

给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环。

请你判断这个图是否是二分图。

输入格式

第一行包含两个整数 n 和 m。

接下来 m 行,每行包含两个整数 u 和 v,表示点 u 和点 v 之间存在一条边。

输出格式

如果给定图是二分图,则输出 Yes,否则输出 No

数据范围

1≤n,m≤10^5

输入样例:
4 4
1 3
1 4
2 3
2 4
输出样例:
Yes

什么叫二分图:

有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接!

说人话的定义:图中点通过移动能分成左右两部分,左侧的点只和右侧的点相连,右侧的点只和左侧的点相连。

思路:

 

图中如果存在奇数环,那么这个图就不是二分图,染色法是一共有两种颜色,把相邻的点染成不同颜色,而我们可以通过染色法来判断这个图是否会出现矛盾,如果矛盾了就不是二分图。

示例代码:

//二分图:图中点通过移动能分成左右两部分,左侧的点只和右侧的点相连,右侧的点只和左侧的点相连

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10,M=2e5+10;

int n,m;
int h[N],e[M],ne[M],idx; //稀疏图用邻接表
int color[N]; //保存每个点的颜色,0是未染色,1是红色,2是黑色

void add(int a,int b) //增加一条a指向b的边
{
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx;
    idx++;
}

bool dfs(int u,int c) //给u点和它所在的连通块进行染色,并返回染色之后这一个连通块是否矛盾的结果(true是没有矛盾)
{
    color[u]=c; //把点u染成c色
    
    for(int i=h[u];i!=-1;i=ne[i])  //遍历u相邻的点
    {
        int j=e[i]; //j是相邻的点的编号
        if(!color[j]) //如果相邻的点没有染色,就递归处理这个相邻点
        {
            if(!dfs(j,3-c)) return false; // 3-1=2,如果u的颜色是1,则相邻点染成2,并给它的相邻点也染色
                                          // 3-2=1,如果u的颜色是2,则相邻点染成1,并给它的相邻点也染色
            //如果给相邻点染色发生错误,就有矛盾
        }
        else if(color[j]==c) return false; //如果相邻点染色和u点颜色一样,就出现了矛盾
    }
    return true;
}

int main()
{
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof(h));
    
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);  //无向图
    }
    
    bool flag=true;
    for(int i=1;i<=n;i++) //遍历所有点
    {
        if(!color[i]) //如果这个点还没有染色
        {
            if(!dfs(i,1)) //把这个点染成1号色,并递归处理所有相邻点
            {
                flag=false; //出现了矛盾(相邻的点染了一样的色)
                break;
            }
        }
    }
    
    if(flag) puts("Yes"); //染色没有矛盾,即为二分图
    else puts("No");
    return 0;
}

注意:

bool dfs(int u,int c) //给u点和它所在的连通块进行染色,并返回染色之后这一个连通块是否矛盾的结果(true是没有矛盾)
{
    color[u]=c; //把点u染成c色
    
    for(int i=h[u];i!=-1;i=ne[i])  //遍历u相邻的点
    {
        int j=e[i]; //j是相邻的点的编号
        if(!color[j]) //如果相邻的点没有染色,就递归处理这个相邻点
        {
            if(!dfs(j,3-c)) return false; // 3-1=2,如果u的颜色是1,则相邻点染成2,并给它的相邻点也染色
                                          // 3-2=1,如果u的颜色是2,则相邻点染成1,并给它的相邻点也染色
            //如果给相邻点染色发生错误,就有矛盾
        }
        else if(color[j]==c) return false; //如果相邻点染色和u点颜色一样,就出现了矛盾
    }
    return true;
}

上面这段dfs代码是给当前点和所在的连通块染色,并判断染完色这个连通块有没有出现矛盾,矛盾了就不是二分图。 

参考:AcWing 860. 染色法判定二分图---详细代码注释+图解 - AcWing

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值