考虑把行和列作为点,每个点作为一条边,这样问题就变成给定一个二分图,要求给每条边染成红色或蓝色,每个点的邻边中数目差不超过
1
1
1。
这里给一个基于欧拉回路的构造,对于原图的每个连通块,我们给里面的奇点两两配对连一条虚边,然后求一条欧拉回路,将上面的边交错染色,注意需要从奇点开始dfs。讨论一下就知道这样是正确的。
时间复杂度
O
(
n
)
\mathcal O(n)
O(n)。
#include <bits/stdc++.h>
#define last last2
using namespace std;
struct Edge {
int t,next;
Edge() {}
Edge(int a,int b):t(a),next(b) {}
};
Edge e[1000005];
int head[400005],n,tot;
bool vis[400005];
inline void addEdge(int x,int y) {
e[++tot]=Edge(y,head[x]);
head[x]=tot;
e[++tot]=Edge(x,head[y]);
head[y]=tot;
}
bool ans[200005],s;
bool d[400005],vis2[400005];
int node[400005],dfs_cnt;
void dfs1(int x) {
vis2[x]=1;
if (d[x]) node[++dfs_cnt]=x;
for(int i=head[x];i;i=e[i].next)
if (!vis2[e[i].t]) dfs1(e[i].t);
}
void dfs2(int x) {
for(int &i=head[x];i;i=e[i].next)
if (!vis[(i+1)>>1]) {
int t=((i+1)>>1);
vis[t]=1;
dfs2(e[i].t);
s^=1;
if (t<=n) ans[t]=s;
}
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
int x,y;
scanf("%d%d",&x,&y);
addEdge(x,200000+y);
d[x]^=1;d[200000+y]^=1;
}
for(int i=1;i<=400000;i++)
if (!vis2[i]) {
dfs_cnt=0;
dfs1(i);
for(int j=1;j<=dfs_cnt;j+=2) addEdge(node[j],node[j+1]);
dfs2((dfs_cnt)?node[1]:i);
}
for(int i=1;i<=n;i++) putchar((ans[i])?'r':'b');
printf("\n");
return 0;
}