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;
}
posted @ 2017-12-07 21:03  AOQNRMGYXLMV  阅读(354)  评论(0编辑  收藏  举报