[SOJ #696]染色(2019-11-10考试)/[Atcoder MUJIN Programming Challenge C]Orange Graph

题目大意

有一个(n)个点(m)条边的简单无向连通图,初始为白色,可以执行操作让一些边变黑,要求使得操作后的图不存在黑色的奇环,且不能使得其他的任何变黑而还符合要求。问最后有多少可能结果。(nleqslant 21)(n-1leqslant mleqslant dfrac{n(n-1)}2)(原题中(nleqslant 16)

题解

因为不存在黑色的奇环,那么最后的黑边组成的图一定可以黑白染色,所以一定是一张二分图。又因为若最后黑图不连通,在两个环之间连一条边不会产生奇环,所以图一定连通。可以枚举每个点的颜色,若两个颜色不同的点之间有白边,改为黑色,最后判断黑图是否连通即可。原题判断连通是(O(n+m))(mathrm{dfs}),其实可以通过一些方法变为(O(n))(weng\_weijie)在拉这道题的时候加强的),故总复杂度(O(2^nn))

卡点

C++ Code:

#include <cstdio>
#include <iostream>
#include <algorithm>
const int N = 21;

int n, m, E[N], ans, vis, S;
void dfs(int u) {
	vis |= 1 << u;
	for (int i = E[u] & ~vis & (S >> u & 1 ? ~S : S); i; i = i & i - 1 & ~vis)
		dfs(__builtin_ctz(i));
}
int main() {
	std::ios::sync_with_stdio(0), std::cin.tie(0);
	std::cin >> n >> m; const int U = 1 << (n - 1), I = (1 << n) - 1;
	for (int i = 0, a, b; i < m; ++i)
		std::cin >> a >> b, --a, --b, E[a] |= 1 << b, E[b] |= 1 << a;
	for (S = 0; S < U; ++S) dfs(vis = 0), ans += vis == I;
	std::cout << ans << '
';
	return 0;
}
原文地址:https://www.cnblogs.com/Memory-of-winter/p/11846513.html