Codeforce 547 D. Mike and Fish(歐拉回路 + 思維 + 構造)

在這裏插入圖片描述


題目大意:二維平面上有 n 個點,對這 n 個點進行黑白染色,使得每行每列都滿足 黑色的點和白色的點的個數的差值 小於等於 1.


按行列連邊構成一張二分圖,X部爲 x 座標, Y部爲 y 座標,一個點的座標爲 (x,y),則連一條從 x 到 y 的邊。

問題轉化爲對邊進行染色,使得任意一個點所連的邊中,黑色和白色的差值的絕對值不超過 1。

每一個點具有偶數度是無向圖具有歐拉回路的充分必要條件,若在二分圖上滿足這個重複必要條件,則可以在這個二分圖上構造一條歐拉回路,每條(x,y)邊作爲入邊時染成黑色,作爲出邊時染成白色。

這樣構造一定滿足條件,每一個節點連出去的邊一定有一半被染成黑色,一半被染成白色。

對於二分圖上奇度數的節點,分別在 X 部和 Y部 構造一個虛點,將它們分別連一條邊到虛點上,使得最後可以構造歐拉回路。

可以觀察到 X 部奇度數的點的個數的奇偶性,和Y部的相同,使用歸納法證明:

當只有一條邊時:顯然成立,X 部和 Y 部各有一個節點具有奇度數。
假設二分圖有 n 條邊時,結論也成立。
當 n = n + 1 時,新加的邊必然使得X部和Y部的 奇度數的點的個數的奇偶性同時改變

因此可以證得兩邊具有奇度數的點的個數的奇偶性一定相同,基於這個性質,爲 X,Y分別構建一個虛點,奇度數的點向虛點連邊,最後一定能構造出一個具有歐拉回路的二分圖。


關於實現:
構造歐拉回路使用 圈套圈算法(就是暴力):任選一個起點,從起點開始 dfs 遍歷,對每條走過的邊打標記,當一個點再無其它邊可走,回溯時將這個點壓入棧中,最後棧中節點的逆序就是歐拉回路0。

歐拉回路考慮的是每條邊只經過一次,但每個點能經過多次,已經經過的邊如果下次訪問到這個點時又被考慮,那麼這條邊會被訪問多次(判斷它能不能走),會被T爆,需要刪邊。

使用前向星實現時,只需要每次更改頭指針 head 即可,遍歷的條件也要改成 i = head[u](而不是原來的 i = nxt[i],否則即使更改了 head,每條邊也可以被訪問多次,最差還是能卡到 n2n^2

具體見代碼:


代碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
const int N = 2e5;
#define pii pair<int,int>
#define fir first
#define sec second
map<pii,int> mp;
int n,vis[maxn << 2],use[maxn << 2],d[maxn << 2],ans[maxn << 2];
int head[maxn << 2],to[maxn << 2],id[maxn << 2],nxt[maxn << 2],cnt;
vector<int> sta,X,Y;
void add(int u,int v,int p) {
	to[cnt] = v;
	nxt[cnt] = head[u];
	id[cnt] = p;
	head[u] = cnt++;
	
	to[cnt] = u;
	nxt[cnt] = head[v];
	id[cnt] = p;
	head[v] = cnt++;
}
void dfs(int u) {
	use[u] = 1;
	for(int i = head[u]; i + 1; i = head[u]) {			//這個地方必須更改,不然一條邊會訪問多次
		head[u] = nxt[i];
		if(vis[id[i]]) continue;
		vis[id[i]] = 1;
		dfs(to[i]);
	}
	sta.push_back(u);
}
int main() {
	scanf("%d",&n);
	int p = -1;
	memset(head,-1,sizeof head);
	for(int i = 1,x,y; i <= n; i++) {
		scanf("%d%d",&x,&y);
		y += N;
		d[x] ^= 1, d[y] ^= 1;
		mp[pii(x,y)] = i;
		add(x,y,i);
		X.push_back(x);
		Y.push_back(y);
	}
	int cnt = 0,s = 0,t = 3 * N + 1;
	for(auto it : X) {
		if(d[it]) {
			cnt++;
			add(it,t,cnt + n);
			d[it] ^= 1,d[t] ^= 1;
		}
	}
	for(auto it : Y) {
		if(d[it]) {
			cnt++;
			add(it,s,cnt + n);
			d[s] ^= 1, d[it] ^= 1;
		}
	}
	if(d[s]) {
		cnt++;
		add(s,t,cnt + n);
		d[s] ^= 1, d[t] ^= 1;
	}
	for(auto it : X)
		if(!use[it]) dfs(it);
	int color = 0;
	for(int i = sta.size() - 2; i >= 0; i--) {
		int u = sta[i + 1],v = sta[i];
		if(u > v) swap(u,v);
		if(!mp.count(pii(u,v)))  {
			color ^= 1;
			continue;
		}
		ans[mp[pii(u,v)]] = color;
		color ^= 1;
	}
	for(int i = 1; i <= n; i++) {
		if(ans[i] == 0) putchar('b');
		else putchar('r');
	}
	putchar('\n');
	return 0;
}
發佈了326 篇原創文章 · 獲贊 10 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章