二分图染色学习笔记

本质上就是一个 BFS

模板题目地址

算法简介

二分图是这样一个图:
有两顶点集且图中每条边的的两个顶点分别位于两个顶点集中,每个顶点集中没有边直接相连接!
无向图 G 为二分图的充分必要条件是, G 至少有两个顶点,且其所有回路的长度均为偶数。
判断二分图的常见方法是染色法: 开始对任意一未染色的顶点染色,之后判断其相邻的顶点中,若未染色则将其染上和相邻顶点不同的颜色, 若已经染色且颜色和相邻顶点的颜色相同则说明不是二分图,若颜色不同则继续判断,bfs和dfs可以搞定!

——百度百科

算法流程

我一般习惯用 BFS 做二分图染色,因为这样会更好理解。

  1. 首先我们确定一个搜索的起点start,一般我确定为 1
  2. 将这个起点Push()进你的广搜队列中,并将它随便指定为一种颜色(即染色),我一般习惯用1-1。要注意的是尽量不要使用0,因为染色的color[]数组同时兼顾着vis[]数组的作用。
  3. 每次在队列中取出队头,并遍历每一条与它相连的边。
    A. 如果当前邻接点 被染过与它相同的颜色,则直接失败。
    B. 如果当前节点没被染过色,就将它加入队列。
    C. 不管当前邻接点 染没染过色,将它染上与当前节点不同的颜色。
  4. 如果整个过程没有失败,则染色成功。

题目描述

PDF源文件

输入输出格式

输入格式:

输出格式:

输入输出样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3
3
0 1
1 2
2 0
3
2
0 1
1 2
9
8
0 1
0 2
0 3
0 4
0 5
0 6
0 7
0 8
0
1
2
3
NOT BICOLORABLE.
BICOLORABLE.
BICOLORABLE.

解题思路

见上

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* -- Basic Headers -- */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>

/* -- STL Iterators -- */
#include <vector>
#include <string>
#include <stack>
#include <queue>

/* -- External Headers -- */
#include <map>
#include <cmath>

/* -- Defined Functions -- */
#define For(a,x,y) for (int a = x; a <= y; ++a)
#define Forw(a,x,y) for (int a = x; a < y; ++a)
#define Bak(a,y,x) for (int a = y; a >= x; --a)
#define RED 1;
#define BLUE -1;

namespace FastIO {

inline int getint() {
int s = 0, x = 1;
char ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') x = -1;
ch = getchar();
}
while (isdigit(ch)) {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * x;
}
inline void __basic_putint(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x >= 10) __basic_putint(x / 10);
putchar(x % 10 + '0');
}

inline void putint(int x, char external) {
__basic_putint(x);
putchar(external);
}
}


namespace Solution {
const int MAXN = 200 + 10;
const int MAXM = MAXN * MAXN + 10;

struct Node {
int now, weight;

Node() { now = weight = 0; }
bool operator < (const Node &that) const {
return weight > that.weight;
}
};

struct Edge {
int now, next;

Edge() { now = next = 0; }
} edge[MAXM];

int head[MAXN], cnt, n, l;
short color[MAXN];

inline void Init() {
cnt = 0;
memset(head, 0, sizeof(head));
memset(color, 0, sizeof(color));
for (int i = 1; i <= cnt + 5; ++i) {
Edge tmp;
tmp.now = tmp.next = 0;
edge[i] = tmp;
}
}

inline void addEdge(int prev, int next) {
edge[++cnt].now = next;
edge[cnt].next = head[prev];
head[prev] = cnt;
}

inline bool BoynextdoorFirstSearch(int start = 1) {
std::queue<int> q;
q.push(start);
color[start] = RED;
while (!q.empty()) {
int now = q.front();
q.pop();
for (int e = head[now]; e; e = edge[e].next) {
int to = edge[e].now;
if (color[to] == color[now]) return false;
if (color[to] == 0) q.push(to);
if (color[now] == 1) {
color[to] = -1;
} else {
color[to] = 1;
}
}
}
return true;
}
}

signed main() {
#define HANDWER_FILE
#ifndef HANDWER_FILE
freopen("testdata.in", "r", stdin);
freopen("testdata.out", "w", stdout);
#endif
using namespace Solution;
using FastIO::getint;
while (true) {
n = getint();
if (n == 0) break;
l = getint();
Init();
for (int i = 1; i <= l; ++i) {
int prev = getint();
int next = getint();
addEdge(prev, next);
addEdge(next, prev);
}
if (BoynextdoorFirstSearch()) puts("BICOLORABLE.");
else puts("NOT BICOLORABLE.");
}
return 0;
}