Codeforces 986C - AND Graph(dfs)

Codeforces 题面传送门 & 洛谷题面传送门

考虑 DFS 一遍遍历每个连通块。

当我们遍历到一个点 \(x\) 时,我们就建立一个虚点 \((2^n-1-x)'\) 表示我们要访问 \(2^n-1-x\) 的所有子集表示的点。

而当我们遍历到某个虚点 \(x'\),我们就枚举每一位 \(b\),如果 \(x\) 的第 \(b\) 位是 \(1\) 则继续遍历 \((x-2^b)'\)。如果其对应的实点存在,即 \(\exists i,s.t.a_i=x\),那么我们就继续遍历实点 \(x\),如果一个点被访问过就直接 return

显然这样能够遍历到连通块中每个点,而每个点最多被遍历一次,因此总复杂度 \(\mathcal O(2^n)\)

题虽 trivial,但是这个建虚点的思想还是很值得研究的。

using namespace fastio;
const int MAXN=1<<23;
int n,m,vis[MAXN+5],has[MAXN+5];
void dfs(int x){
	if(vis[x]) return;vis[x]=1;
	if(x<(1<<n)) dfs((1<<n)+(((1<<n)-1)^x));
	else{
		if(has[x-(1<<n)]) dfs(x-(1<<n));
		for(int j=0;j<n;j++) if(x>>j&1) dfs(x^(1<<j));
	}
}
int main(){
	read(n);read(m);int res=0;
	for(int i=1,x;i<=m;i++) read(x),has[x]=1;
	for(int i=0;i<(1<<n);i++) if(has[i]&&!vis[i]) res++,dfs(i);
	printf("%d\n",res);
	return 0;
}
posted @ 2021-10-17 22:41  tzc_wk  阅读(58)  评论(0)    收藏  举报