首页 > 试题广场 >

二分图判定

[编程题]二分图判定
  • 热度指数:1956 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}给定一张包含 n 个节点、m 条无向边的图(不保证连通)。若存在一种方式可将每个节点染为黑色或白色,使得任意一条边的两个端点颜色不同,则称该图为二分图
\hspace{15pt}请判断所给图是否为二分图。

【名词解释】
\hspace{15pt}二分图:可将顶点集合划分为两个独立集,且所有边均连接不同集合的图。

输入描述:
\hspace{15pt}第一行输入两个整数 n,m\left(1\leqq n,m\leqq 10^{5}\right)——节点数与边数。 
\hspace{15pt}接下来的 m 行,每行输入两个整数 u_i,v_i\left(1\leqq u_i,v_i\leqq n\right),表示存在一条连接 u_iv_i 的无向边。保证无重边、自环。


输出描述:
\hspace{15pt}若该图为二分图,输出Yes;否则输出No。
示例1

输入

5 7
1 2
2 3
3 4
4 1
4 5
5 2

输出

Yes

说明

如图,把1, 3, 5点染色为白,2, 4染色为黑,即可满足二分图要求,所以这个图是二分图。
示例2

输入

5 4
1 2
2 3
3 1
4 5

输出

No

说明

1, 2, 3号点无论如何染色都无法满足要求,所以不是二分图。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum { UNKNOWN = 0, BLACK = 1, WHITE = 2 } Color;

typedef struct {
  int to;
  int next;
} Edge;

void addEdge(int* head, Edge* edges, int u, int v, int i) {
  (*(edges + i)).next = *(head + u);
  (*(edges + i)).to = v;
  *(head + u) = i;
}

void printAdjList(int* head, Edge* edges, const int n) {
  int i, u;
  for (u = 1; u <= n; ++u) {
    fprintf(stdout, "vertex %d: [ ", u);
    for (i = *(head + u); i; i = (*(edges + i)).next)
      fprintf(stdout, "%d ", (*(edges + i)).to);
    fputs("]\n", stdout);
  }
  fputc(10, stdout);
}

int dfs(int* head, Edge* edges, int curr, Color color, Color* colors) {
  *(colors + curr) = color;
  int i, nei;
  for (i = *(head + curr); i; i = (*(edges + i)).next) {
    nei = (*(edges + i)).to;
    if (*(colors + nei) == color) return 0; // 我邻居的颜色与我相同,表明存在着冲突
    if (*(colors + nei) == UNKNOWN && 
        !dfs(head, edges, nei, color == BLACK ? WHITE : BLACK, colors))
      return 0;
  }
  return 1;
}

int main(const int argc, const char* argv[]) {
  int n, m, u, v;
  fscanf(stdin, "%d %d", &n, &m);
  
  int head[n + 1]; 
  Edge edges[m << 1 | 1];
  memset(head, 0x0000, sizeof head);
  
  int i = 0;
  while (m--) {
    fscanf(stdin, "%d %d", &u, &v);
    addEdge(head, edges, u, v, ++i);
    addEdge(head, edges, v, u, ++i);
  }
  
  Color colors[n + 1];
  memset(colors, UNKNOWN, sizeof colors);
  
  // 图中可能有多个连通分量 (连通分量 == 极大的连通子图)
  for (u = 1; u <= n; ++u)
    if (*(colors + u) == UNKNOWN && !dfs(head, edges, u, BLACK, colors))
      return fputs("No", stdout), 0;
  
  return fputs("Yes", stdout), 0;
}

发表于 2021-07-17 16:18:59 回复(0)