zoukankan      html  css  js  c++  java
  • 二分图判定

    概述

    若一个无向图的结点可以分为不相交的两个部分使得每条边的两个端点分别在不同的部分,则称这样的无向图为二分图(bipartite graph)

    算法:黑白二着色(bicoloring)

    扫描所有结点,从未访问过的结点开始,将其为染色邻接点染为不同的染色。若已染色的邻接点与当前结点颜色相同,则该图不是二分图;反之该图是二分图

    理解

    扫描所有结点,从未访问过的结点开始

    无向图不一定连通!故需要扫描所有结点进行DFS或BFS。

    此外显然二分图是可合并的,任意无向图是二分图当且仅当其各个连通分量都是二分图(若均为二分图,则每个二分图的两个子集可以合并;否则无法找到两个集合满足每条边的两端点分别在两个集合)

    若已染色的邻接点与当前结点颜色相同,则该图不是二分图;反之该图是二分图

    从这个图可以很清楚的看出,由二分图的定义可知,任意一个点通过一条边只能走到另一个集合中的点,一条边的两个端点的颜色一定不同。上述算法的正确性是显然的

    模板

    小tip:这里我把颜色定为1和2,可以用异或3代替3-

    但注意选择的颜色不能和数组的初始化值相同!否则无法判定是否已被染色

    DFS可能会栈溢出,所以这里给出BFS版代码

     1 #include<cstdio>
     2 #include<cctype>
     3 using namespace std;
     4 #define re register int
     5 int read()
     6 {
     7     int f=0,x=0;
     8     char c=getchar();
     9     while(!isdigit(c))
    10     {
    11         f=f|c=='-';
    12         c=getchar();
    13     }
    14     while(isdigit(c))
    15     {
    16         x=(x<<1)+(x<<3)+(c^48);
    17         c=getchar();
    18     }
    19     return x;
    20 }
    21 struct edge
    22 {
    23     int to,pre;
    24 }edges[1000001];
    25 int head[1000001],tot;
    26 int n,m;
    27 int queue[1000001],left=1,right=0;
    28 int color[1000001];//表示每个点的颜色(1为白,2为黑) 
    29 bool bipartite()
    30 {
    31     for(int i=1;i<=n;i++)
    32         if(!color[i])
    33         {
    34             queue[++right]=i;
    35             color[i]=1;
    36             while(right>=left)
    37             {
    38                 int x=queue[left++];
    39                 for(int j=head[x];j;j=edges[j].pre)
    40                     if(color[edges[j].to]==color[x])
    41                         return false;
    42                     else if(!color[edges[j].to])
    43                     {
    44                         color[edges[j].to]=3^color[x];
    45                         queue[++right]=edges[j].to;
    46                     }
    47             }
    48         }
    49     return true;
    50 }
    51 void add(int x,int y)//邻接表存边 
    52 {
    53     edges[++tot].to=y;
    54     edges[tot].pre=head[x];
    55     head[x]=tot;
    56 }
    57 int main()
    58 {
    59     scanf("%d%d",&n,&m);
    60     for(int i=1;i<=m;i++)
    61     {
    62         int x,y;
    63         scanf("%d%d",&x,&y);
    64         add(x,y),add(y,x);
    65     }
    66     printf("%d
    ",bipartite());
    67     return 0;
    68 }
    二分图判定
  • 相关阅读:
    Vue 中样式穿透 /deep/
    Vue 数据冻结 Object.freeze
    Vue 启动项目内存溢出
    Typora[ markdown ] 使用3之----- 语法高亮显示
    Typora[ markdown ] 使用2之-----空格显示
    手动创建mysql数据库的语句记录
    api不能自动注入条件的解决方法
    【WTM框架】查询列表显示正常,但是导出的时候查询条件不起作用的问题记录及解决方法
    WTM问题之“数据列表”控件出现横向的滚动条的解决方法
    树莓派docker无法限制内存Your kernel does not support memory limit capabilities or the cgroup is not mounted
  • 原文地址:https://www.cnblogs.com/LiHaozhe/p/9530162.html
Copyright © 2011-2022 走看看