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

题目大意

有一个\(n\)个点\(m\)条边的简单无向连通图,初始为白色,可以执行操作让一些边变黑,要求使得操作后的图不存在黑色的奇环,且不能使得其他的任何变黑而还符合要求。问最后有多少可能结果。\(n\leqslant 21\)\(n-1\leqslant m\leqslant \dfrac{n(n-1)}2\)(原题中\(n\leqslant 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 << '\n';
	return 0;
}
posted @ 2019-11-13 06:55  Memory_of_winter  阅读(223)  评论(0编辑  收藏  举报