给定一个由n个点,m条边组成的无向图(注意,此图可能不连通),对任意1 ≤ i ≤ m存在一条边连接u[i], v[i]。回答此图是不是二分图。二分图定义为存在一种给图中每一个点染上黑白两色其中之一的着色方式,使得对每一对有边直接相连的点颜色不同。
第一行输入为N和M,代表无向图的点数和边数。
接下来M行,表示M条边,每一行两个整数u[i], v[i],满足1 ≤ u[i], v[i] ≤ n,保证图中无重边,自环。
其中保证1 ≤ N, M ≤ 100000
一行字符串,为Yes,或者No。
Yes表示输入图是二分图。
No表示输入图不是二分图。
5 7 1 2 2 3 3 4 4 1 4 5 5 2
Yes
如图,把1, 3, 5点染色为白,2, 4染色为黑,即可满足二分图要求,所以这个图是二分图。
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; }