2020/11/10 二分法染色

题目

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

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

输入格式
第一行包含两个整数n和m。

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

输出格式
如果给定图是二分图,则输出“Yes”,否则输出“No”。

数据范围
1≤n,m≤105
输入样例:
4 4
1 3
1 4
2 3
2 4
输出样例:
Yes

算法分析

二分法其实跟遍历算法有很大的结合关系.对于一个连通域的来说,遍历算法都是可以全部遍历,而在遍历的过程中为每一个节点交叉染色,就实现了二分染色.一旦发现应染为1色的结点被染为2色那就说明无法进行二分.也就是说,起一个头其实是可以一起染出一块连通域的. 但是由于图内可能是有很多个连通域,因此我们先随便找一个结点染色(此时他属于的连通域全被染色,如果没有问题的话),再遍历其他未染色的结点,重新染色,这样其他连通域也会被逐渐染色.到最后,其实不会有没有被染色的结点,只有染色失败(重复)的报错,从而判定是否是二分图.

源代码

import java.util.*;
class Main{
    static int N=100010;
    static int M=200010;
    static int index=0;
    static int[] h=new int[N];
    static int[] e=new int[M];
    static int[] ne=new int[M];
    static int[] color=new int[N];
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int m=sc.nextInt();
        while(m-->0){
            int u=sc.nextInt();
            int v=sc.nextInt();
            add(u,v);
            add(v,u);
        }
        boolean flag=true;
        for(int i=1;i<=n;i++){
            if(color[i]==0) {
                if(!dfs(i,1)) {
                flag=false;
                break;}
            }
        }
        if(flag) System.out.print("Yes");
        else System.out.print("No");
        
    }
    public static void add(int u,int v){
        e[++index]=v;
        ne[index]=h[u];
        h[u]=index;
    }
    public static boolean dfs(int u,int c){
        color[u]=c;
        for(int i=h[u];i!=0;i=ne[i]){
            int j=e[i];
            if(color[j]==c) return false ;
            else if(color[j]==0){
                if(!dfs(j,3-c)) return false;
            }
        }
        return true;
    }
    
}

代码特别说明

  • 对于无向图,添加时要添加两遍,同时,在设定边的大小时也要为给定边数的两倍
  • 对于关键代码的思路解释:
    首先确定函数dfs(u,c)的含义是给节点u染色为c,并以此染其连通域所有的点,成功返回true,失败返回false,步骤:
  1. 给当前节点染色
  2. 找到其邻节点,邻节点有两个状态
  • 没有被染色: 那么此时就以这个节点为头来染色(满足邻节点不同色的条件),失败返回true
  • 被染色了:那就看看这个被染色的结点颜色是不是我们期待的,不是则返回false
  1. 当所有结点全部遍历结束,并且没有中途返回false,那么就说明这个连通域染色成功,返回false
  • 因为我们需要对邻节点进行操作,所以用邻接表存储
  • 最后判定的时候,如前面所说,只需要找到没有染色的结点来对其连通域染色即可.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值