Codeforces Round #485 (Div. 2) - F - AND Graph

传送门:点击打开链接

题意:给n和m,还有m个互不相同的数,均小于1<<n,如果m个数字中a & b = 0,那么a 和b有边相连,问有多少个连通分量。

分析:把每个数看做一个01集合,对于在m个数中的数,求它的补集的子集个数即可这里用4位来举个例子,比如5(0101),补集:(1010),补集的子集:(1010)  (1000) (0010) (0000)补集的子集和该集合的&运算的结果为0,满足条件。那么就可以枚举0 - ((1<<n) - 1)进行DFS即可。每次找到所有联通的点。时间复杂度O(1<<n)。注意反码和按位取反的区别。反码不需要对符号位取反,按位取反是对所有位取反。计算机内部在做数学运算时(也就是计算机的0和1的运算),都是以补码为标准的,说白了 计算机中就一种码那就是补码,而现实社会中的编码规则,例如原码、反码都是我们自定义的,为了和计算机中的补码形成转换关系。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,vis[1<<23],ct[1<<23];

void dfs(int x) {
    if(vis[x]) return ;
    vis[x]=1;
    for(int i=0;i<n;i++)
        if( x & (1<<i) )
            dfs( x^(1<<i));
    if(ct[x]) dfs( ((1<<n)-1) & (~x));
}

int main() {
    cin>>n>>m;
    for(int i=0;i<m;i++) {
        int num;
        cin>>num;
        ct[num]=1;
    }
    int ans=0;
    for(int i=0;i<(1<<n);i++)
        if(ct[i] && !vis[i])
            dfs( ((1<<n)-1) & (~i)),ans++;
    cout<<ans<<endl;
}

参考博客:https://www.cnblogs.com/fzl194/p/9112965.html

https://blog.csdn.net/coder__cs/article/details/79186677

猜你喜欢

转载自blog.csdn.net/tianwei0822/article/details/80560531