【大联盟】20230706 T2 graph(graph) QOJ4635 【Graph Operation】

题解

赛时得分:60/? 写了个乱搞

首先考虑无解的条件。注意到一次操作后,所有点的度数都没有改变,所以无解的充分条件就是存在一个点的度数在两张图中不相等。接下来尝试构造策略,使得度数相等的时候都能出解。

我们可以将题意转化一下,变为对图 \(G\) 和图 \(H\) 都可以操作,使得最后产生的两张图相等。输出答案时,只需先输出在 \(G\) 上的操作,再倒序输出在图 \(H\) 上的操作的逆操作即可。

考虑类似增量构造,我们按编号从小到大扫点。扫到点 \(i\) 时,我们找出所有在 \(G\) 中有、在 \(H\) 中没有的边以及所有在 \(H\) 中有、在 \(G\) 中没有的边。由于两张图 \(i\) 号点的度数相同,所以我们对这些边两两配对。

假设要删边的点在 \(G\) 中有、在 \(H\) 中没有的边为 \((i,a)\),在 \(H\) 中有、在 \(G\) 中没有的边为 \((i,b)\)。有两种方案:

  1. \(G\) 中删除 \((i,a)\),同时添加 \((i,b)\),这就需要在 \(G\) 中找到一个点 \(t\) 满足 \(a\nsim t,b\sim t\),然后在 \(G\) 操作 \((i,a,b,t)\)
  2. \(H\) 中添加 \((i,a)\),同时删除 \((i,b)\),这就需要在 \(H\) 中找到一个点 \(t\) 满足 \(a\sim t,b\nsim t\),然后在 \(H\) 操作 \((i,b,a,t)\)

那么,现在我们得说明两种方案一定有一种可行。设 \(N_G(x)\) 表示点 \(x\) 在图 \(G\) 中邻居的集合,\(N_H(x)\) 同理。

若方案 1 不可行,说明 \(N_G(b)\subseteq N_G(a)\),又因为 \(G\) 中有 \((i,a)\)\(G\) 中没有 \((i,b)\),所以 \(N_G(w)\subsetneq N_G(v)\),所以 \(|N_G(a)| > |N_G(b)|\)。同理可得,若方案 2 也不可行,\(|N_H(b)| > |N_H(a)|\),又因为度数相同 \(|N_G(a)|=|N_H(a)|,|N_G(b)|=|N_H(b)|\),所以矛盾。

考虑用 bitset 优化找点过程。

时间复杂度 \(O(\frac{n^3}{\omega})\)

代码

#include <bits/stdc++.h>
#define SZ(x) (int) x.size() - 1
#define all(x) x.begin(), x.end()
#define ms(x, y) memset(x, y, sizeof x)
#define F(i, x, y) for (int i = (x); i <= (y); i++)
#define DF(i, x, y) for (int i = (x); i >= (y); i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T> void chkmax(T& x, T y) { x = max(x, y); }
template <typename T> void chkmin(T& x, T y) { x = min(x, y); }
template <typename T> void read(T &x) {
	x = 0; int f = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
const int N = 1010;
bitset <N> g[N], h[N];
int n, m, dg[N], dh[N];
vector <pair <pair <int, int>, pair <int, int>>> ansg, ansh;
signed main() {
	freopen("graph.in", "r", stdin);
	freopen("graph.out", "w", stdout);
	read(n), read(m);
	F(i, 1, m) {
		int x, y; read(x), read(y);
		dg[x]++, dg[y]++;
		g[x][y] = g[y][x] = true;
	}
	F(i, 1, m) {
		int x, y; read(x), read(y);
		dh[x]++, dh[y]++;
		h[x][y] = h[y][x] = true;
	}
	F(i, 1, n)
		if (dg[i] != dh[i]) {
			puts("-1");
			return 0;
		}
	F(i, 1, n) {
		vector <int> tj, tk;
		F(j, i + 1, n) {
			if (g[i][j] && !h[i][j]) tj.push_back(j);
			if (!g[i][j] && h[i][j]) tk.push_back(j);
		}
		F(j, 0, SZ(tj)) {
			bitset <N> t = (~g[tj[j]]) & g[tk[j]];
			t[i] = t[tj[j]] = t[tk[j]] = false;
			int pos = t._Find_first();
			if (pos <= n) {
				ansg.emplace_back(make_pair(i, tj[j]), make_pair(tk[j], pos));
				g[i][tj[j]] = g[tj[j]][i] = g[tk[j]][pos] = g[pos][tk[j]] = false;
				g[i][tk[j]] = g[tk[j]][i] = g[tj[j]][pos] = g[pos][tj[j]] = true;
				continue;
			}
			t = h[tj[j]] & (~h[tk[j]]);
			t[i] = t[tj[j]] = t[tk[j]] = false;
			pos = t._Find_first();
			if (pos <= n) {
				ansh.emplace_back(make_pair(i, tj[j]), make_pair(tk[j], pos));
				h[i][tk[j]] = h[tk[j]][i] = h[tj[j]][pos] = h[pos][tj[j]] = false;
				h[i][tj[j]] = h[tj[j]][i] = h[tk[j]][pos] = h[pos][tk[j]] = true;
				continue;
			} assert(false);
		}
		F(j, 1, n) {
			h[i][j] = h[j][i] = g[i][j] = g[j][i] = false;
		}
	}
	cout << ansg.size() + ansh.size() << endl;
	for (auto i: ansg) cout << i.first.first << " " << i.first.second << " " << i.second.first << " " << i.second.second << endl;
	reverse(all(ansh));
	for (auto i: ansh) cout << i.first.first << " " << i.first.second << " " << i.second.first << " " << i.second.second << endl;
	return 0;
}
posted @ 2023-07-22 17:25  zhaohaikun  阅读(24)  评论(0编辑  收藏  举报