Codeforces 986C AND Graph dfs
Posted zhouzhendong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 986C AND Graph dfs相关的知识,希望对你有一定的参考价值。
原文链接https://www.cnblogs.com/zhouzhendong/p/9161514.html
题目传送门 - Codeforces 986C
题意
给定 $n,m (0leq nleq 22,1leq mleq 2^n)$ 。
接下来给定 $m$ 个数,记第 $i$ 个数为 $a_i$ ,对于所有 $a_i$ ,满足 $0leq a_ileq 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的主要内容,如果未能解决你的问题,请参考以下文章
CodeForces 915D Almost Acyclic Graph
codeforces 715B:Complete The Graph