首页 > 试题广场 >

【模板】二分图结构Ⅰ-A ‖ 染色判定:DFS

[编程题]【模板】二分图结构Ⅰ-A ‖ 染色判定:DFS
  • 热度指数:2337 时间限制:C/C++ 5秒,其他语言10秒 空间限制:C/C++ 1024M,其他语言2048M
  • 算法知识视频讲解
\hspace{15pt}对于给定的由 n 个顶点、m 条边构成的无向连通图,判定其是否为二分图

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

输入描述:
\hspace{15pt}第一行输入两个整数 n,m \left( 1 \leqq n, m \leqq 3 \times 10^5\right) 代表顶点数量、边数量。
\hspace{15pt}此后 m 行,第 i 行输入两个整数 u_iv_i \left( 1 \leqq u_i, v_i \leqq n;\ u_i \neq v_i \right),表示图上第 i 条边双向连接顶点 u_iv_i

\hspace{15pt}图可能存在重边。不存在自环、保证连通。


输出描述:
\hspace{15pt}如果给定的图不是一张二分图,输出 \texttt{NO};否则输出 \texttt{YES}
示例1

输入

5 6
1 2
2 3
3 4
4 1
4 5
5 2

输出

YES

说明

\hspace{15pt}在这个样例中,把顶点 1, 3, 5 点染色为白,2, 4 点染色为黑,即可满足二分图要求,所以这个图是二分图。

图片
示例2

输入

5 4
1 2
2 3
3 1
4 5

输出

NO

说明



备注:
本题已于下方时间节点更新,请注意题解时效性:
1. 2025-07-07 优化题面文本与格式
2. 2025-11-28 第一组样例 m 与实际边数不符,修正。模板题为便于测试,将时间限制扩充至 5s,空间限制扩充至 1024MB。
3. 2025-12-05 对题面与数据进行了微调,以匹配整套模板题(n,m10^5 增加到 3 \times 10^5,输出修改为全大写的 \texttt{YES}\texttt{NO},去除了题面背景,增加了重边数据)。
#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)