Acwing860. 染色法判定二分图

题目

给定一个 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

代码与解析

这是一道经典的图论问题,要判断一个无向图是否是二分图。二分图是指能够将图的所有节点分成两个不相交的子集,使得同一子集内的节点不相邻。

一开始的思路可以从图的遍历入手,遍历每个节点,如果该节点没有被染色,则使用深度优先搜索(DFS对其进行染色,并通过递归的方式对其邻接节点进行染色。染色的规则是如果当前节点染色为1,则其邻接节点染色为2,反之亦然。如果在染色过程中发现相邻节点已经染色,并且颜色相同,则说明不是二分图,返回false。最终遍历完所有节点,如果没有发现不符合规则的情况,则返回true

import java.util.Arrays;
import java.util.Scanner;

public class Main {
    static int N = 100010, M = 200010;
    static int n, m;
    static int[] h = new int[N], e = new int[M], ne = new int[M], color = new int[N];
    static int idx;

    // 添加一条边,构建邻接表
    public static void add(int a, int b) {
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }

    // 深度优先搜索染色
    public static boolean dfs(int u, int c) {
        color[u] = c;

        for (int i = h[u]; i != -1; i = ne[i]) {
            int j = e[i];
            if (color[j] == 0) {
                if (!dfs(j, 3 - c)) return false;  // 递归对邻接节点染色
            } else if (color[j] == c) {
                return false;  // 邻接节点颜色相同,不是二分图
            }
        }

        return true;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();

        Arrays.fill(h, -1);

        // 构建图
        for (int i = 0; i < m; i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            add(a, b);
            add(b, a);
        }

        boolean flag = true;
        // 对每个节点进行DFS染色
        for (int i = 1; i <= n; i++) {
            if (color[i] == 0) {
                if (!dfs(i, 1)) {  // 如果染色失败,不是二分图
                    flag = false;
                    break;
                }
            }
        }

        // 输出结果
        if (flag) {
            System.out.println("Yes");
        } else {
            System.out.println("No");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值