【算法】二分图判定

news2024/11/16 10:44:37

目录

  • 1.概述
  • 2.代码实现
  • 3.应用

本文参考:
LABULADONG 的算法网站

1.概述

(1)二分图 (Bipartite Graph),又称为二部图,是图论中的一种特殊模型。 设 G = (V, E) 是一个无向图,如果顶点 V 可分割为两个互不相交的子集 A 和 B,并且图中的每条边 (i, j) 所关联的两个顶点 i 和 j 分别属于这两个不同的顶点集,则称图 G 为一个二分图。

(2)二分图的判定其实就等同于图的双色问题,双色问题即:给你一幅图,请你用两种颜色将图中的所有顶点着色,且使得任意一条边的两个端点的颜色都不相同,你能做到吗?

(3)例如,下图就是一个二分图。
在这里插入图片描述

2.代码实现

(1)使用 BFS 来判定二分图的代码实现如下:

import java.util.LinkedList;
import java.util.Queue;

class Solution {
    // flag 用于标记该图是否为二分图
    boolean flag = true;
    // color 记录图中节点的颜色,false 和 true 分别代表两种不同的颜色
    boolean[] color;
    // visited 记录图中的节点是否被访问过
    boolean[] visited;
    
    // adjMatrix 为邻接矩阵
    public boolean isBipartite(int[][] adjMatrix) {
        //n 为节点个数
        int n = adjMatrix.length;
        //初始化
        color = new boolean[n];
        visited = new boolean[n];
        /*
            因为图不一定是联通的,可能存在多个子图,所以要把每个节点都作为起点进行一次遍历
            如果发现任何一个子图不是二分图,整幅图都不算二分图
        */
        for (int v = 0; v < n; v++) {
            if (!visited[v]) {
                bfs(adjMatrix, v);
            }
        }
        return flag;
    }
    
    //BFS
    public void bfs(int[][] adjMatrix, int start) {
        //定义队列
        Queue<Integer> queue = new LinkedList<>();
        //当前节点已经被访问
        visited[start] = true;
        //将当前节点存入队列中
        queue.offer(start);
        while (!queue.isEmpty() && flag) {
            //取出队首节点
            int v = queue.poll();
            //遍历与 v 相邻的所有节点
            for (int w : adjMatrix[v]) {
                if (!visited[w]) {
                    //相邻节点 w 没有被访问过,则应该给 w 涂上与 v 不同的颜色
                    color[w] = !color[v];
                    //节点 w 已经被访问
                    visited[w] = true;
                    //将节点 w 存入队列
                    queue.offer(w);
                } else {
                    //相邻节点 w 没有被访问过,则应该判断 w 与 v 的颜色是否相同
                    if (color[w] == color[v]) {
                        // v 和 w 的颜色相同,则说明该图不是二分图,令 flag = false,然后直接返回即可
                        flag = false;
                        return;
                    }
                }
            }
        }
    }
}

(2)使用 DFS 来判定二分图的代码实现如下:

class Solution {
    // flag 用于标记该图是否为二分图
    boolean flag = true;
    // color 记录图中节点的颜色,false 和 true 分别代表两种不同的颜色
    boolean[] color;
    // visited 记录图中的节点是否被访问过
    boolean[] visited;
    
    // adjMatrix 为邻接矩阵
    public boolean isBipartite(int[][] adjMatrix) {
        //n 为节点个数
        int n = adjMatrix.length;
        //初始化
        color = new boolean[n];
        visited = new boolean[n];
        /*
            因为图不一定是联通的,可能存在多个子图,所以要把每个节点都作为起点进行一次遍历
            如果发现任何一个子图不是二分图,整幅图都不算二分图
        */
        for (int v = 0; v < n; v++) {
            if (visited[v] == false) {
                dfs(adjMatrix, v);
            }
        }
        return flag;
    }
    
    //DFS
    public void dfs(int[][] adjMatrix, int v) {
        if (flag == false) {
            //如果已经确定该图不是二分图,则直接返回即可
            return;
        }
        //当前节点已经被访问
        visited[v] = true;
        for (int w : adjMatrix[v]) {
            if (visited[w] == false) {
                //相邻节点 w 没有被访问过,则应该给 w 涂上与 v 不同的颜色
                color[w] = !color[v];
                //继续遍历与 w 相邻的所有节点
                dfs(adjMatrix, w);
            } else {
                //相邻节点 w 没有被访问过,则应该判断 w 与 v 的颜色是否相同
                if (color[w] == color[v]) {
                    //v 和 w 的颜色相同,则说明该图不是二分图,令 flag = false,然后直接返回即可
                    flag = false;
                    return;
                }
            }
        }
    }
}

有关 BFS 的具体细节可以参考【算法】广度优先遍历 (BFS) 这篇文章。
有关 DFS 的具体细节可以参考【算法】深度优先遍历 (DFS) 这篇文章。

3.应用

(1)LeetCode 中的886.可能的二分法这题便是对二分图判定的应用:

在这里插入图片描述

该题的本质就是二分图的判定,只不过本题需要先通过数组 dislikes 来构建图,代码实现如下:

class Solution {
    //flag 用于标记该图是否为二分图
    boolean flag = true;
    //color 记录图中节点的颜色,false 和 true 分别代表两种不同的颜色
    boolean[] color;
    //visited 记录图中的节点是否被访问过
    boolean[] visited;

    public boolean possibleBipartition(int n, int[][] dislikes) {
        //初始化,节点编号从 1 开始
        color = new boolean[n + 1];
        visited = new boolean[n + 1];
        //构建图
        List<Integer>[] graph = buildGraph(n, dislikes);
        for (int v = 1; v <= n; v++) {
            if (!visited[v]) {
                DFS(v, graph);
            }
        }
        return flag;
    }

    /*
        利用题目所给信息构建无向图,通过邻接表存储
        其中 n 表示节点个数,dislikes 存储节点之间的关系 
    */
    public List<Integer>[] buildGraph(int n, int[][] dislikes) {
        //图节点编号为 1...n
        List<Integer>[] graph = new LinkedList[n + 1];
        //创建 n 个节点
        for (int i = 1; i <= n; i++) {
            graph[i] = new LinkedList<>();
        }
        //创建节点之间的关系(即无向边)
        for (int[] edge : dislikes) {
            int v = edge[1];
            int w = edge[0];
            //无向图相当于双向图
            // v -> w
            graph[v].add(w);
            // w -> v
            graph[w].add(v);
        }
        return graph;
    }

    public void DFS(int v, List<Integer>[] graph) {
        if (flag == false) {
            return;
        }
        visited[v] = true;
        for (int w : graph[v]) {
            if (visited[w] == false) {
                //节点 w 未被访问过
                color[w] = !color[v];
                DFS(w, graph);
            } else {
                //节点 w 已被访问过
                if (color[w] == color[v]) {
                    flag = false;
                    return;
                }
            }
        }
    }
}

(2)大家可以去 LeetCode 上找相关的二分图判定的题目来练习,或者也可以直接查看LeetCode算法刷题目录(Java)这篇文章中的二分图章节。如果大家发现文章中的错误之处,可在评论区中指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/160772.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity 和vs2022对接问题

第一个问题&#xff1a;在vs中编写好的程序在unity中预览出现乱码&#xff1b;提示&#xff1a;只要是乱码的问题90%离不开编码表Unity中的编码表是utf-8,而vs中默认的应该是GB2312。英文还好&#xff0c;中文可定就会出现乱码&#xff0c;解决方法也很简单&#xff1a;把vs中的…

【Python基础四】入门级朋友看的超详教程

前言 这是最后一篇基础的文章啦 往期文章&#xff1a; 【Python基础一】入门级朋友看的超详教程 【Python基础二】入门级朋友看的超详教程 【Python基础三】入门级朋友看的超详教程 刚开始接触Python的宝子&#xff0c;有什么不懂的都可以私信我哦 我还准备了大量的免费…

目标检测:YOLO V2思路解读

目标检测&#xff1a;YOLO V2思路解读YOLO V1存在的问题主要改进Batch NormalizationHigh Resolution ClassifierConvolutional With Anchor BoxesDimension ClusterDirect location PredictionFine-Grained FeaturesMulti-Scale TrainingLoss FunctionYOLO V1存在的问题 对于…

使用Redis代替Session实现短信登陆

1.集群的Session共享问题 多台Tomcat并不共享Session存储空间&#xff0c;当请求切换到不同tomcat服务器时会导致数据丢失&#xff1a; 当用户量增多&#xff0c;我们需要进行负载均衡、对tomcat做水平扩展&#xff0c;可是存储在Tomcat里的Session不是共享的&#xff0c;这…

从C和C++内存管理来谈谈JVM的垃圾回收算法设计-上

从C和C内存管理来谈谈JVM的垃圾回收算法设计-上引言C内存模型malloc堆内存分配过程malloc为什么结合使用brk和mmapmalloc如何通过内存池管理Heap区域垃圾收集器引言 本文想和大家来探讨一下JVM是如何对堆内存进行管理和垃圾回收,相关书籍如深入理解JVM第三版中已经介绍过了相关…

OSCP-Vulnhub靶机记录-digitalworldlocal-fall

Vulnhub靶机记录-digitalworldlocal-fall靶机描述安装扫描枚举使用kali自带的FUZZ权限提升靶机描述 靶机地址&#xff1a;https://www.vulnhub.com/entry/digitalworldlocal-fall,726/ Description To celebrate the fifth year that the author has survived his infosec ca…

也来聊聊滑块验证码的那些事

单位做攻防演习&#xff0c;我扮演攻击方尝试破解。发现滑块验证码做了升级&#xff0c;比之前复杂了很多。好在仍然是一维验证&#xff0c;不用太麻烦。https接口里读出的是json对象&#xff0c;先从对象里取出图片转的base64编码&#xff0c;然后把字符串转回成numpy.ndarray…

Verilog HDL 基础语法

一、逻辑值 0: 逻辑低电平&#xff0c;条件为假 1: 逻辑高电平&#xff0c;条件为真 z: 高阻态&#xff0c;无驱动 x: 未知逻辑电平二、实际例子 1. 模块名一般与文件名相同 线网型变量会被映射成一条真实存在的物理连线。 寄存器型变量会被映射成一个寄存器。 2. 参数 para…

2、JavaScript快速入门

2.1 引入JavaScript 内部标签 <!-- 在script标签内写JavaScript(简称js)代码&#xff0c;代码块可以放在head中&#xff0c;也可以放在body中--> <script>// alert:弹窗alert(Hello,world!); //注意以分号结尾 </script>外部引入 hello.js alert(Hello,worl…

分享120个ASP源码,总有一款适合您

ASP源码 分享120个ASP源码&#xff0c;总有一款适合您 链接&#xff1a;https://pan.baidu.com/s/1WwTsUTLS_qLvP-TC1w-1vQ?pwdvxpk 提取码&#xff1a;vxpk 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载…

OB0207 obsidian 自动获取url链接:auto-link-title插件使用

序号解读&#xff1a; 01——软件基础使用、基础语法 02——插件使用 03——综合实战 0 写在前面 Ob社区插件汇总&#xff1a;Airtable - OB社区插件汇总 - Johnny整理 - 每周更新 - B站 Johnny学Explore the "OB社区插件汇总 - Johnny整理 - 每周更新 - B站 Johnny学&qu…

过去一年渲染了3亿帧,助力了63.81亿票房、1150亿播放量丨瑞云渲染年度大事记

2022年&#xff0c;注定是充满未知和挑战的一年。抗疫三年&#xff0c;终于在2022年底迎来放开&#xff0c;我们怀着忐忑的心情告别了核酸、行程码和封控&#xff0c;成为了自己健康的第一负责人。这段时间大家应该都忙着和病毒做斗争吧&#xff0c;瑞云各个岗位的小伙伴们也都…

6.7、万维网(如HTTP超文本传输协议)

1、基本介绍 万维网 WWW (World Wide Web&#xff09;并非某种特殊的计算机网络\color{red}并非某种特殊的计算机网络并非某种特殊的计算机网络。 它是一个大规模的、联机式的信息储藏所&#xff0c;是运行在因特网上的一个分布式应用。 万维网利用网页之间的超链接\color{r…

Web进阶:Day5 移动适配、rem、less

Web进阶&#xff1a;Day5 Date: January 10, 2023 Summary: 移动适配、rem、less 移动适配 移动适配指网页元素的宽高都要随着设备宽度等比缩放 rem &#xff1a; 目前多数企业在用的解决方案 vw / vh&#xff1a;未来的解决方案 rem 目标&#xff1a;能够使用rem单位设置网…

2022年跨境物流指数研究报告

第一章 行业概况 指提供跨境物流服务的行业。跨境物流是指在电子商务环境下&#xff0c;依靠互联网、大数据、信息化与计算机等先进技术&#xff0c;物品从跨境电商企业流向跨境消费者的跨越不同国家或地区的物流活动。 图 物流运输行业产业链结构图 资料来源&#xff1a;资产…

Tapdata Cloud 场景通关系列:集成阿里云计算巢,实现一键云上部署真正开箱即用

【前言】作为中国的 “Fivetran/Airbyte”, Tapdata Cloud 自去年发布云版公测以来&#xff0c;吸引了近万名用户的注册使用。应社区用户上生产系统的要求&#xff0c;Tapdata Cloud 3.0 将正式推出商业版服务&#xff0c;提供对生产系统的 SLA 支撑。Tapdata 目前专注在实时数…

VS2010 安装NuGet NPIO 基础连接已经关闭:发送时发生错误

1.下载Nuget并安装 NuGet Package Manager - Visual Studio Marketplace 工具->扩展管理器可看见 2.安装NPOI 3. 如果遇见基础连接已经关闭:发送时发生错误 要把https://packages.nuget.org/改为https://www.nuget.org/api/v2/ VS2019要使用https://www.nuget.org/api/v…

OAuth2.0 详解

OAuth2.0介绍 OAuth&#xff08;Open Authorization&#xff09;是一个关于授权&#xff08;authorization&#xff09;的开放网络标准&#xff0c;允许用户授权第三方 应用访问他们存储在另外的服务提供者上的信息&#xff0c;而不需要将用户名和密码提供给第三方移动应用或分…

【日常系列】LeetCode《26·动态规划1》

数据规模->时间复杂度 <10^4 &#x1f62e;(n^2) <10^7:o(nlogn) <10^8:o(n) 10^8<:o(logn),o(1) lc 509【剑指 10-1】&#xff1a;斐波那契数列问题 - 动态规划入门 https://leetcode.cn/problems/fibonacci-number/ 提示&#xff1a; 0 < n < 30 #方案…

WebSocket概念及实现简易聊天室

WebSocket实现简易聊天室 1 WebSocket介绍 网络通信协议是HTML5开始提供的一个单个TCP连接上进行全双工通信协议 1.1 诞生原因&#xff08;http无状态、无连接&#xff09; ①HTTP协议&#xff1a; 由于HTTP协议是一种无状态、无连接、单向的应用层协议&#xff0c;通信请求只…