zoukankan      html  css  js  c++  java
  • [BZOJ1130] [POI2008]POD Subdivision of Kingdom

    Description

    给出一个具有N个结点的无向图,将其分成两个集合S1,S2. 这两个集合的点的个数一样多,但连接它们的边最少.

    Input

    第一行给出数字N,M,代表有N个点,M条边. 下面M行,每行两个数字代表此两点间有条边.

    Output

    输出的点集应包含1,且按升序排列

    Sample Input

    6 8
    1 2
    1 6
    2 3
    2 5
    2 6
    3 4
    4 5
    5 6

    Sample Output

    1 2 6

    HINT

    N<=26

     

     
    我还以为是状压DP...
    因为$inom{26}{13}$很小,所以可以直接爆搜。
    我们每次从集合T内抽取一个点放入S内,直到S, T中都只有n/2个元素。
    每次抽出一个点都计算这个点对答案产生的贡献。
    问题是如何在$O(1)$的时间内算出贡献。
    显然一个点从S到T内,会减去它与S之间的边,加上与T之间的边。
    我们对每个点用一个二进制数表示它所连的点的状态,然后和集合状态取与就是应该减去/加上的边的状态。
    然后统计数量直接预处理出每个二进制数的1的个数,但是1<<26太大了数组开不下。
    只统计1<<13以内的二进制数的1的个数,然后把状态拆成两半分别计算。
     

     
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    #include <bitset>
    using namespace std;
    #define reg register 
    #define gc getchar
    inline int read() {
        int res=0;char ch=gc();bool fu=0;
        while(!isdigit(ch)){if(ch=='-')fu=1;ch=gc();}
        while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=gc();
        return fu?-res:res;
    }
    
    int n, m;
    int bin[27], cb[1<<14];
    int sit[29];
    int ans = 1e9, ansS;
    
    int Count(int x) {
        return cb[x>>13] + cb[(bin[13] - 1) & x];
    }
    
    void dfs(int lst, int s1, int s2, int now, int num)
    {
        if (num == n / 2) {
            if (now < ans) ans = now, ansS = s1;
            return ;
        }
        for (reg int i = lst ; i <= n ; i ++)
        {
            if (!(s2 & bin[i - 1])) continue;
            dfs(i + 1, s1 + bin[i - 1], s2 - bin[i - 1], now - Count(sit[i] & s1) + Count(sit[i] & s2), num + 1);
        }
    }
    
    int main()
    {
        n = read(), m = read();
        bin[0] = 1;
        for (reg int i = 1 ; i <= 26 ; i ++) bin[i] = bin[i - 1] << 1;
        for (reg int i = 1 ; i < bin[13] ; i ++) cb[i] = cb[i >> 1] + (i & 1);
        for (reg int i = 1 ; i <= m ; i ++)
        {
            int x = read(), y = read();
            sit[x] |= bin[y - 1];
            sit[y] |= bin[x - 1];
        }
        dfs(1, 0, bin[n] - 1, 0, 0);
        if (!(ansS & bin[0])) ansS = (bin[n] - 1) ^ ansS;
        for (reg int i = 1 ; i <= n ; i ++)
            if (ansS & bin[i - 1]) printf("%d ", i);
        return 0;
    }
  • 相关阅读:
    5.对象的简化属性
    7.函数参数默认值
    python中argparse
    VC 6.0 打开文件出错
    【UNIX程序设计教程】 阅读初体验(1)
    引以为鉴ARM开发板连线注意事项
    windows xp宿主机 + Linux 虚拟机 网络配置
    Gcc编译选项分析
    ADS下调试出现的警告信息
    S3C2440串口通讯实现
  • 原文地址:https://www.cnblogs.com/BriMon/p/9785729.html
Copyright © 2011-2022 走看看