CodeForces 547D Mike and Fish 思维
题意:
二维平面上给出\(n\)个点,然后对每个点进行染色:红色和蓝色,要求位于同一行或同一列的点中,红色点和蓝色点的个数相差不超过1
分析:
正解是求欧拉路径,在这篇博客中看到一个巧妙的思路:
对于同一行中的点,进行两两分组,每组的两个点之间连一条边(可能会剩下孤立点)。
同样地,同一列中的点,也进行两两分组,每组的两个点之间也连一条边。
将每条边的端点染上不同的颜色就满足了题目中的要求了。
为什么可以将得到的图进行二分染色呢?
这样的连接方式,保证了每个点左右两边最多有一边的点与其相连,上下两边最多有一边的点与其相连。
也就是每个点的度数最大为\(2\),这样这张图就是由若干条链和链首尾闭合变成的简单环组成的。
我们知道奇数长度的环是不能二分染色的
这些环还有个特点就是,相邻的两条边是互相垂直的,所以要想闭合的话,其边数一定为偶数。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
#define PB push_back
#define PII pair<int, int>
#define REP(i, a, b) for(int i = a; i < b; i++)
#define PER(i, a, b) for(int i = b - 1; i >= a; i--)
#define ALL(x) x.begin(), x.end()
const int maxn = 200000 + 10;
vector<int> row[maxn], col[maxn], G[maxn];
char ans[maxn];
struct Point {
int x, y, id;
void read() { scanf("%d%d", &x, &y); }
bool operator < (const Point& t) const {
return x < t.x || (x == t.x && y < t.y);
}
};
bool cmp(const Point& A, const Point& B) {
return A.y < B.y || (A.y == B.y && A.x < B.x);
}
Point p[maxn];
void dfs(int u, int p = -1, int c = 0) {
ans[u] = c ? 'r' : 'b';
for(int v : G[u]) if(v != p && !ans[v])
dfs(v, u, c ^ 1);
}
int main() {
int n; scanf("%d", &n);
REP(i, 0, n) {
p[i].read();
p[i].id = i;
}
sort(p, p + n);
for(int i = 0, j; i < n; i = j) {
for(j = i; j < n && p[j].x == p[i].x; j++);
for(int k = i + 1; k < j; k += 2) {
G[p[k].id].PB(p[k-1].id);
G[p[k-1].id].PB(p[k].id);
}
}
sort(p, p + n, cmp);
for(int i = 0, j; i < n; i = j) {
for(j = i; j < n && p[j].y == p[i].y; j++);
for(int k = i + 1; k < j; k += 2) {
G[p[k].id].PB(p[k-1].id);
G[p[k-1].id].PB(p[k].id);
}
}
REP(i, 0, n) if(!ans[i]) dfs(i);
ans[n] = 0;
printf("%s\n", ans);
return 0;
}