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 }

 

posted @ 2018-05-31 14:42  menhera  阅读(333)  评论(0编辑  收藏  举报