码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces 986C AND Graph dfs

时间:2018-06-09 23:20:01      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:pre   出现   连通性   force   targe   统计   $0   ret   codeforce   

原文链接https://www.cnblogs.com/zhouzhendong/p/9161514.html

题目传送门 - Codeforces 986C

题意

  给定 $n,m (0\leq n\leq 22,1\leq m\leq 2^n)$ 。

  接下来给定 $m$ 个数,记第 $i$ 个数为 $a_i$ ,对于所有 $a_i$ ,满足 $0\leq a_i\leq 2^n$ 。

  第 $i$ 个数与第 $j$ 个数有无向边,当且仅当 $a_i\ AND\ a_j=0$ 。其中 $"AND"$ 是按位与。

  问在以这 $m$ 个数为节点的无向图中有多少个各自独立的连通块。

题解

  考虑有有连边的条件。

  我们记 $"AND"$ 为按位与运算, $"OR"$ 为按位或运算, $"XOR"$ 为按位异或运算。

  我们记 $s=2^n-1$ 。

  如果 $a$ 与 $b$ 有连边,那么满足 $b \in {x| x\ OR\ (s\ XOR\ a) = (s\ XOR\ a) }$。

  于是我们考虑记忆化dfs。

  我们用 $v[y]$ 表示集合 ${x|x\ OR\ y=y}$ 是否被访问过。

  在 dfs 的过程中,dfs 一个 $y$ ,我们就要访问其所有子集。

  如果当前的 $y$ 在 $a$ 数组中出现过,那么我们确定了上一个数与当前数的连通关系,而且我们要继续 dfs,在 $ s\ XOR\ y $ 代表的集合中 dfs 查找是否有新的数字连通。

  由于连通性具有传递性和对称性,所以每次dfs可以排除一块连通块。

  然后就简单统计一下就可以了。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1<<22;
int n,m,s,a[N],f[N],v[N];
void dfs(int x){
	if (v[x])
		return;
	v[x]=1;
	if (f[x])
		dfs(s^x);
	for (int i=0;i<n;i++)
		if (x&(1<<i))
			dfs(x^(1<<i));
}
int main(){
	scanf("%d%d",&n,&m);
	s=(1<<n)-1;
	memset(f,0,sizeof f);
	memset(v,0,sizeof v);
	for (int i=1;i<=m;i++)
		scanf("%d",&a[i]),f[a[i]]=1;
	int ans=0;
	for (int i=1;i<=m;i++)
		if (!v[a[i]]){
			v[a[i]]=1;
			dfs(s^a[i]);
			ans++;
		}
	printf("%d",ans);
	return 0;
}

  

  

Codeforces 986C AND Graph dfs

标签:pre   出现   连通性   force   targe   统计   $0   ret   codeforce   

原文地址:https://www.cnblogs.com/zhouzhendong/p/9161514.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!