CodeForces 1656I Neighbour Ordering

洛谷传送门

CF 传送门

首先显然每个点双独立,所以不同点双构造后直接合并即可。下面只考虑图点双连通的情况。

发现一个环显然有解。一个环加一条边也有解(例如 \((1, 2), (2, 3), (3, 4), (4, 1), (1, 3)\))。

发现一个环连出去一条链再连回来就无解(例如 \((1, 2), (2, 3), (3, 4), (4, 1), (2, 5), (5, 4)\))。

由此可见,图有哈密顿回路是有解的必要条件。

那么假设可以求出这个哈密顿回路,发现有两条交叉的边也无解了(例如 \((1, 2), (2, 3), (3, 4), (4, 1), (1, 3), (2, 4)\))。所以图是一个平面图。进一步地,图是一个广义串并联图

所以我们可以用缩二度点、叠重边的方法先把整个图缩成一条边(一个二元环)。然后把这个过程反过来变成加边,就能得到一条哈密顿回路。

然后发现此时一定有解。每个点的出边极角排序即可。

时间复杂度 \(O(n \log n)\)

启示:若直接构造毫无思路,不妨考虑一些不能构造的情况,除去这些情况说不定会有很好的性质。

code
// Problem: I. Neighbour Ordering
// Contest: Codeforces - CodeTON Round 1 (Div. 1 + Div. 2, Rated, Prizes!)
// URL: https://codeforces.com/problemset/problem/1656/I
// Memory Limit: 256 MB
// Time Limit: 5000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<int, int> pii;

const int maxn = 300100;

int n, m, nt, dfn[maxn], low[maxn], stk[maxn], top, tim, bel[maxn];
int deg[maxn], nxt[maxn], id[maxn];
vector<int> G[maxn], ans[maxn], scc[maxn], T[maxn];
vector<pii> E[maxn];
set<int> S[maxn];

void dfs(int u, int fa) {
	dfn[u] = low[u] = ++tim;
	stk[++top] = u;
	for (int v : G[u]) {
		if (v == fa) {
			continue;
		}
		if (!dfn[v]) {
			dfs(v, u);
			low[u] = min(low[u], low[v]);
			if (low[v] >= dfn[u]) {
				scc[++nt].pb(u);
				while (1) {
					int x = stk[top--];
					bel[x] = nt;
					scc[nt].pb(x);
					if (x == v) {
						break;
					}
				}
			}
		} else {
			low[u] = min(low[u], dfn[v]);
		}
	}
}

struct node {
	int u, x, y;
	node(int a = 0, int b = 0, int c = 0) : u(a), x(b), y(c) {}
} a[maxn];

void solve() {
	scanf("%d%d", &n, &m);
	top = tim = nt = 0;
	for (int i = 1; i <= n; ++i) {
		vector<int>().swap(G[i]);
		vector<int>().swap(ans[i]);
		vector<int>().swap(scc[i]);
		vector<pii>().swap(E[i]);
		dfn[i] = low[i] = stk[i] = bel[i] = 0;
	}
	while (m--) {
		int u, v;
		scanf("%d%d", &u, &v);
		++u;
		++v;
		G[u].pb(v);
		G[v].pb(u);
	}
	for (int i = 1; i <= n; ++i) {
		if (!dfn[i]) {
			dfs(i, -1);
		}
	}
	for (int i = 1; i <= n; ++i) {
		for (int j : G[i]) {
			if (dfn[i] > dfn[j]) {
				E[bel[i]].pb(i, j);
			}
		}
	}
	for (int t = 1; t <= nt; ++t) {
		for (int i : scc[t]) {
			S[i].clear();
			deg[i] = 0;
			vector<int>().swap(T[i]);
		}
		for (pii e : E[t]) {
			int u = e.fst, v = e.scd;
			S[u].insert(v);
			S[v].insert(u);
			T[u].pb(v);
			T[v].pb(u);
			++deg[u];
			++deg[v];
		}
		queue<int> q;
		for (int i : scc[t]) {
			if (deg[i] == 2) {
				q.push(i);
			}
		}
		int tot = 0;
		while (q.size()) {
			int u = q.front();
			q.pop();
			int x = *S[u].begin(), y = *S[u].rbegin();
			if (x == y) {
				break;
			}
			deg[u] = 0;
			a[++tot] = node(u, x, y);
			S[x].erase(u);
			S[y].erase(u);
			if (S[x].find(y) != S[x].end()) {
				if ((--deg[x]) == 2) {
					q.push(x);
				}
				if ((--deg[y]) == 2) {
					q.push(y);
				}
			} else {
				S[x].insert(y);
				S[y].insert(x);
			}
		}
		if (tot != (int)scc[t].size() - 2) {
			puts("NO");
			return;
		}
		vector<int> vc;
		for (int i : scc[t]) {
			if (deg[i] == 1) {
				vc.pb(i);
			}
		}
		nxt[vc[0]] = vc[1];
		nxt[vc[1]] = vc[0];
		for (int i = tot; i; --i) {
			int u = a[i].u, x = a[i].x, y = a[i].y;
			if (nxt[x] != y && nxt[y] != x) {
				puts("NO");
				return;
			}
			if (nxt[x] != y) {
				swap(x, y);
			}
			nxt[x] = u;
			nxt[u] = y;
		}
		int x = scc[t][0];
		for (int i = 1; i <= (int)scc[t].size(); ++i) {
			id[x] = i;
			x = nxt[x];
		}
		for (int i : scc[t]) {
			sort(T[i].begin(), T[i].end(), [&](int x, int y) {
				int u = id[x], v = id[y];
				if (u < id[i]) {
					u += (int)scc[t].size();
				}
				if (v < id[i]) {
					v += (int)scc[t].size();
				}
				return u < v;
			});
			for (int j : T[i]) {
				ans[i].pb(j);
			}
		}
	}
	puts("YES");
	for (int i = 1; i <= n; ++i) {
		for (int j : ans[i]) {
			printf("%d ", j - 1);
		}
		putchar('\n');
	}
}

int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2024-01-26 14:24  zltzlt  阅读(43)  评论(0)    收藏  举报