1. 程式人生 > 實用技巧 >Codeforces 1186F. Vus the Cossack and a Graph(歐拉回路)

Codeforces 1186F. Vus the Cossack and a Graph(歐拉回路)

https://codeforces.com/contest/1186/problem/F

題解:

看到這樣的限制不難聯想到歐拉回路(一看就是倒著造的題)。

對每個聯通塊分開考慮。

考慮如果所有點都是偶數,那麼隨便找一個歐拉回路,交叉染色即可。

如果有奇點,建一個新點,奇點向新建中轉點連虛邊,然後跑一條迴路。

虛邊會把路徑劃分成若干段,對每一段都交叉染色,特別地,保證每一段最左最右的邊一定選,因為中間的點必須一選一不選,而旁邊的點度數本來是奇數,可以有一次多選的機會。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 4e6 + 5;

int fi[N], to[N], nt[N], tot = 1;

void link(int x, int y) {
	nt[++ tot] = fi[x], to[tot] = y, fi[x] = tot;
	nt[++ tot] = fi[y], to[tot] = x, fi[y] = tot;
}

int n, m, x, y;

int du[N];

int cur[N], bz[N];

int ans[N][2], ans0;

int d[N], d0;

void dg(int x, int fr) {
	for(; cur[x]; ) {
		int i = cur[x];
		cur[x] = nt[cur[x]];
		if(bz[i]) continue;
		bz[i] = bz[i ^ 1] = 1;
		dg(to[i], i);
	}
	if(fr) d[++ d0] = fr;
}

void work() {
	int la = 0;
	fo(i, 1, d0 + 1) {
		if(i > d0 || d[i] > 2 * m + 1) {
			for(int j = la + 1; j < i; j += 2) {
				ans[++ ans0][0] = to[d[j]];
				ans[ans0][1] = to[d[j] ^ 1];
			}
			if((i - la) % 2 == 1 && la + 1 < i) {
				ans[++ ans0][0] = to[d[i - 1]];
				ans[ans0][1] = to[d[i - 1] ^ 1];
			}
			la = i;
		}
	}
}

int main() {
	scanf("%d %d", &n, &m);
	fo(i, 1, m) {
		scanf("%d %d", &x, &y);
		link(x, y);
		du[x] ++; du[y] ++;
	}
	fo(i, 1, n) if(du[i] & 1) {
		link(n + 1, i);
	}
	fo(i, 1, n + 1) {
		cur[i] = fi[i];
	}
	fo(i, 1, n + 1) {
		d0 = 0;
		dg(i, 0);
		work();
	}
	pp("%d\n", ans0);
	fo(i ,1, ans0) pp("%d %d\n", ans[i][0], ans[i][1]);
}