zoukankan      html  css  js  c++  java
  • CF986C AND Graph

    半年前做的一道题现在还是不会

    x&y=0

    意味着,x的补集的子集都是和x直接相连的

    不妨令图中的点数就是2^n

    那么可以直接从x^((1<<n)-1)开始记忆化爆搜,路上遇到的都是和x直接相连的

    如果遇到一个在给出集合里的数t,就从这个点额外再开一层,t^((1<<n)-1)再开始爆搜

    这样,如果两个点直接或者间接相连,那么一定可以从任意一个点出发搜出整个连通块,并对每个点打上标记

    总共的状态数是2^22。复杂度有保证

    loc只是一个理解,其实不需要

    #include<bits/stdc++.h>
    using namespace std;
    const int N=(1<<22)+10;
    int exi[N];
    bool vis[N];// zuo i youwu vis
    bool has[N];// you i youwu vis
    int cnt,mx,len,up;
    int a[N];
    int n,m;
    void dfs(int x,int loc){
        //cout<<x<<" now "<<cnt<<endl;
        if(loc){
            if(has[x]) return;
            has[x]=1;
            if(exi[x]) {vis[exi[x]]=1;dfs(a[exi[x]],0);}
            for(int i=0;(1<<i)<=x;i++){
                if(x&(1<<i)){
                    dfs(x^(1<<i),1);
                }
            }
        }
        else{
            vis[exi[x]]=1;dfs(up^x,1);
        }
    }
    int main()
    {
        /*lg[0]=0;
        for(int i=1;i<=N-5;i++) lg[i]=(i>>(lg[i-1]+1))?lg[i-1]+1:lg[i-1];*/
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d",&a[i]),exi[a[i]]=i,mx=max(mx,a[i]);
        }
        for(int i=0;i<=23;i++){
            if((1<<i)>mx) break;
            len=i+1;
        }
        up=(1<<len)-1;//cout<<" up "<<up<<endl;
        for(int i=1;i<=m;i++){
            if(!vis[i]) {
                //cout<<"here go "<<i<<" "<<a[i]<<endl;
                cnt++;dfs(up^a[i],1);
            }
        }
        printf("%d",cnt);return 0;
    }
  • 相关阅读:
    阅读ARm芯片手册 阅读方法
    Linux驱动mmap内存映射
    Linux下inotify的基本使用及注意事项
    网络视频监控与人脸识别
    Linux pci驱动源码
    Verilog语法
    跟着我从零开始入门FPGA(一周入门XXOO系列)-1、Verilog语法
    周立功-我的25年嵌入式生涯
    Linux 进程学习
    [转]MFC下关于“建立空文档失败”问题的分析
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10430800.html
Copyright © 2011-2022 走看看