【名词解释】
第一行输入两个整数
代表顶点数量、边数量。
此后
行,第
行输入两个整数
和
,表示图上第
条边双向连接顶点
和
。
图可能存在重边。不存在自环、保证连通。
如果给定的图不是一张二分图,输出
;否则输出
。
5 6 1 2 2 3 3 4 4 1 4 5 5 2
YES
在这个样例中,把顶点
点染色为白,
点染色为黑,即可满足二分图要求,所以这个图是二分图。
5 4 1 2 2 3 3 1 4 5
NO
本题已于下方时间节点更新,请注意题解时效性:
1. 2025-07-07 优化题面文本与格式
2. 2025-11-28 第一组样例与实际边数不符,修正。模板题为便于测试,将时间限制扩充至 5s,空间限制扩充至 1024MB。
3. 2025-12-05 对题面与数据进行了微调,以匹配整套模板题(从
增加到
,输出修改为全大写的
和
,去除了题面背景,增加了重边数据)。
#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;
}