思路:
首先,x & (~x) == 0
其次,~x 的 子集 y = ((~x) ^ (1<<k)), 0<= k < n(如果k这一位是1),y&x == 0
所以枚举 a[i] ,如果a[i]每被标记,搜索 (~a[i])的子集, 子集的子集......,边搜索边标记元素,如果出现一个y也属于a[i],那么再搜索(~y)的子集
这样就能保证一个联通图里的元素都能在一次搜索里被标记完
代码:
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pi acos(-1.0) #define LL long long #define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pii pair<int, int> #define mem(a, b) memset(a, b, sizeof(a)) #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout); //head const int N = 8e6 + 5; int a[N], tot, n; bool hs[N], vis[N]; void dfs(int x) { if(vis[x]) return ; vis[x] = true; if(hs[x]) dfs(tot ^ x); for (int i = 0; i < n; i++) { if(x & (1<<i)) dfs(x ^ (1<<i)); } } int main() { int m; scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) scanf("%d", &a[i]), hs[a[i]] = true; tot = (1<<n) - 1; int ans = 0; for (int i = 1; i <= m; i++) { if(!vis[a[i]]) { ans++; vis[a[i]] = true; dfs(tot ^ a[i]); } } printf("%d ", ans); return 0; }