Codeforces986C AND Graph 【位运算】【dfs】
题目大意:
一张$ m $个编号互异点图,最大不超过$ 2^n $,若两个编号位与为0则连边,问连通块数量。
题目分析:
考虑怎样的两个点会连边。这种说法对于A和B两个点来说,就相当于B在A的0的子集中。我们不妨将A的0用1填充,得到的每一个数取反都是可以与A连边的点,然后这个取反前的数也可以继续填充。重新审视它发现我们从小到大地考虑每个0被1填充是没关系的,因为我们很显然地遍历了所有情况。那么可以做记忆化。时间复杂度$O(n2^n)$.
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 4250000; 5 6 int n,m,ans; 7 int a[maxn],app[maxn]; 8 int arr[maxn][2]; 9 10 void dfs(int now,int dr){ 11 if(arr[now][dr] == 1) return; 12 arr[now][dr] = 1; 13 for(int i=0;i<n;i++){ 14 if(((1<<i) & now) == 0){ 15 dfs(now|(1<<i),dr); 16 } 17 } 18 if(app[(1<<n)-1-now]) arr[(1<<n)-1-now][0] = 1,dfs((1<<n)-1-now,1); 19 } 20 21 void work(){ 22 for(int i=1;i<=m;i++){ 23 if(!arr[a[i]][0]){ 24 ans++;arr[a[i]][0] = 1; 25 dfs(a[i],1); 26 } 27 } 28 } 29 30 int main(){ 31 scanf("%d%d",&n,&m); 32 for(int i=1;i<=m;i++) scanf("%d",&a[i]),app[a[i]] = 1; 33 work(); 34 printf("%d",ans); 35 return 0; 36 }