leetcode_785_判断二分图

题目:

给定一个无向图graph,当这个图为二分图时返回true。

如果我们能将一个图的节点集合分割成两个独立的子集A和B,并使图中的每一条边的两个节点一个来自A集合,一个来自B集合,我们就将这个图称为二分图。

graph将会以邻接表方式给出,graph[i]表示图中与节点i相连的所有节点。每个节点都是一个在0到graph.length-1之间的整数。这图中没有自环和平行边: graph[i] 中不存在i,并且graph[i]中没有重复的值。


示例 1:
输入: [[1,3], [0,2], [1,3], [0,2]]
输出: true
解释: 
无向图如下:
0----1
|    |
|    |
3----2
我们可以将节点分成两组: {0, 2} 和 {1, 3}。

示例 2:
输入: [[1,2,3], [0,2], [0,1,3], [0,2]]
输出: false
解释: 
无向图如下:
0----1
| \  |
|  \ |
3----2
我们不能将节点分割成两个独立的子集。
注意:

graph 的长度范围为 [1, 100]。
graph[i] 中的元素的范围为 [0, graph.length - 1]。
graph[i] 不会包含 i 或者有重复的值。
图是无向的: 如果j 在 graph[i]里边, 那么 i 也会在 graph[j]里边。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/is-graph-bipartite
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


思路:

二分图是离散数学中图论章节的内容。二分图又称二部图,即图(这里指无向图)中的的点,可以划分为两个部分。划分的规则为:连线两端的点分别属于两个部其中的一个。称这样的图为二分图。

在解决该问题时,使用的是染色法。即给点打标签。

打标签的规则为:如果当前点还没有被打上标签,则给其打上与其所有邻点不同的标签;如果当前点已经打上标签则continue。

在实现的时候使用1,2,3三种数字来作为“染剂”染色

由于操作对象是图,并且需要遍历,所以自然的想到DFS(深度优先搜索)和BFS(广度优先搜索)。

而由于操作对象 图 不一定是连通图,所以可能有多个连通分量,这时一次DFS或者BFS就不够,需要使用一个外循环来控制DFS/BFS的入口

for(int i = 0;i < lens;i++){
            if(book[i] == 1) continue;
            book[i] = 1;
            dfs(graph, paint, book, i);
        }

最后,通常的,实现DFS与BFS时都需要使用一个标签book数组来记录已经遍历过的节点。

再由于本题需要给节点打标签,所以额外需要paint数组记录每一个节点的分组情况。


实现:

JAVA版:

package leetcode;

import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

/*
USER:LQY
DATE:2020/7/16
TIME:8:34
*/
public class leetcode_785 {

    public static void main(String []args){
        int [][]graph = {
                {},
                {2,4,6},
                {1,4,8,9},
                {7,8},
                {1,2,8,9},
                {6,9},
                {1,5,7,8,9},
                {3,6,9},
                {2,3,4,6,9},
                {2,4,5,6,7,8}
        };
        System.out.println("\n"+new leetcode_785().isBipartite(graph));
    }
    public boolean isBipartite(int[][] graph) {

        int lens = graph.length;

        int []paint = new int[lens];
        int []book = new int[lens];
//        DFS
//        for(int i = 0;i < lens;i++){
//            if(book[i] == 1) continue;
//            book[i] = 1;
//            dfs(graph, paint, book, i);
//        }
        //BFS
//        LinkedList<Integer> queen = new LinkedList<>();
//        for(int k = 0;k < lens;k++){
//            if(book[k] == 1) continue;
//            queen.addLast(k);
//            while(!queen.isEmpty()){
//                int nv = queen.removeFirst();
            book[nv] = 1;
//                //添加邻边的同时染色
//                int f1 = 0;
//                int f2 = 0;
            int f3 = 0;
//                for(int i = 0;i < graph[nv].length;i++){
//                    int next = graph[nv][i];
//                    if(paint[next] == 1) f1 = 1;
//                    if(paint[next] == 2) f2 = 2;
                if(paint[i] == 3) f3 = 3;
//                    if(book[next] == 1) continue;
//                    queen.addLast(next);
//                    book[next] = 1;
//
//                }
//                //染色
//                if(f1 == 0){
//                    paint[nv] = 1;
//                }else if(f2 == 0){
//                    paint[nv] = 2;
//                }else{
//                    paint[nv] = 3;
//                }
//                System.out.println("点"+nv+"被染成:"+paint[nv]);
//            }
//        }
        for(int i : paint){
            System.out.print(i+" ");
        }
        for(int i = 0;i < lens;i++){
            if(paint[i] == 3){
                return false;
            }
        }
        return true;
    }
    public void dfs(int [][]graph, int []paint, int[]book, int nv) {
        if(paint[nv] != 0) return;
        //先判断该点处是否染色
        int f1 = 0;
        int f2 = 0;
//            int f3 = 0;
        //统计邻边染色情况
        for(int i = 0;i < graph[nv].length;i++){
            int next = graph[nv][i];
            if(paint[next] == 1) f1 = 1;
            if(paint[next] == 2) f2 = 2;
//                if(paint[i] == 3) f3 = 3;
        }
        //染色
        if(f1 == 0){
            paint[nv] = 1;
        }else if(f2 == 0){
            paint[nv] = 2;
        }else{
            paint[nv] = 3;
        }
        System.out.println("点"+nv+"被染成:"+paint[nv]);

        //深搜
        for(int i = 0;i < graph[nv].length;i++){
            int next = graph[nv][i];
            if(book[next] == 1) continue;
            book[next] = 1;
            dfs(graph, paint, book, next);
        }
    }
}

Python版:

class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        lens = len(graph)
        paint = [0 for _ in range(lens)]
        book = [0 for _ in range(lens)]
        for i in range(lens):
            if(book[i] > 0):
                continue
            book[i] = 1
            self.dfs(graph, paint, book, i)

        for i in range(lens):
            if(paint[i] == 3):
                return False
        return True

    def dfs(self, graph: List[List[int]], paint: List[int], book: List[int], nv: int):
        if(paint[nv] > 0):
            return
        f1 = 0
        f2 = 0
        for i in range(0, len(graph[nv])):
            next = graph[nv][i]
            if(paint[next] == 1):
                f1 = 1
            if(paint[next] == 2):
                f2 = 2
        if(f1 == 0):
            paint[nv] = 1
        elif(f2 == 0):
            paint[nv] = 2
        else:
            paint[nv] = 3
        for i in range(0, len(graph[nv])):
            next = graph[nv][i]
            if(book[next] == 1):
                continue
            book[next] = 1
            self.dfs(graph, paint, book, next)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值