题意:一个平面上有n个点,先要求对每个点进行红蓝染色,且满足以下条件:对于任意一横行或一竖列,上面的红点和蓝点的个数之差最多为1。题目保证有解。
题解:出题人的解法有点厉害。。但是cubelove的做法更神。。被治愈了。。
做法1:将x坐标和y坐标分别放到两个点集中。如果有点(a,b),那么x点集中的a和y点集中的b连边。然后会有一个图。每条边都代表一个点。现在问题等价于对每个边染色,使得对于两个点集中的任意一个点所连的边的两种颜色的个数之差不大于1。如果所有点的度都为偶数,那么跑一遍欧拉回路,然后对走过的边轮流染红蓝。如果有的点的度数为奇数,那么就暂时先删掉它的某条边,然后归结于子问题,将其它的点按此种方法染色好以后,再考虑当时去的边应该染什么颜色。
做法2:考虑以下性质:如果某行或某列中有k个点,那么可以对这k个点加上[k/2]条边,使得每个点最多连了一条边。此时对每条边两端染不同的颜色就解决了。如果有孤立点,任意染色。所以我们可以这样对x方向和y方向操作,然后连边。最后对每个点dfs一下,保证每条边的两边的颜色不同,答案就出来了。
被做法2治愈了。。。
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=201111;
vector<int> v[N];
int t[N],a[N][2];
void dfs(int x,int y){
if(t[x]) return ;
t[x]=y;
for(int i=0;i<v[x].size();i++) dfs(v[x][i],3-y);
}
int main()
{
int i,j,n,x,y;
scanf("%d",&n);
for(i=1;i<=n;i++){
for(j=0;j<2;j++){
scanf("%d",&x);
if(a[x][j]){
v[i].pb(a[x][j]);
v[a[x][j]].pb(i);
a[x][j]=0;
}else a[x][j]=i;
}
}
for(i=1;i<=n;i++) dfs(i,1),putchar(t[i]>1?'r':'b');
}