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;
    }
  • 相关阅读:
    nowcoderD Xieldy And His Password
    Codeforces681D Gifts by the List
    nowcoder80D applese的生日
    Codeforces961E Tufurama
    Codeforces957 Mahmoud and Ehab and yet another xor task
    nowcoder82E 无向图中的最短距离
    nowcoder82B 区间的连续段
    Codeforces903E Swapping Characters
    Codeforces614C Peter and Snow Blower
    Codeforces614D Skills
  • 原文地址:https://www.cnblogs.com/BriMon/p/9785729.html
Copyright © 2011-2022 走看看