zoukankan      html  css  js  c++  java
  • SPOJ11469 Subset(折半枚举)

    题意

    给定一个集合,有多少个非空子集,能划分成和相等的两份。$nleq 20$

    题解

    看到这个题,首先能想到的是$3n$的暴力枚举,枚举当前元素是放入左边还是放入右边或者根本不放,但是显然是不可取的,看到$n$只有20,考虑折半搜索,将集合分成两部分,每个部分$3{frac{n}{2}}$枚举。

    接着考虑如何合并,在枚举时计一个$delta$表示此时左边和右边的差值,这样在右半部分每一次枚举完后我们可以直接在左半部分查找是否存在一个$delta$相等,如果相等,则两个集合的并集满足条件

    #include <map>
    #include <vector>
    #include <cstdio>
    typedef long long ll;
    
    template <typename T>
    inline void read(T &x) {
        x = 0; char ch = getchar();
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    }
    
    const int N = 21;
    int n, m, a[N], cnt, ans;
    std::map <int, int> Ma;
    std::vector <int> S[1 << N];
    bool ok[1 << N];
    
    void dfs1(int i, int s, int d) {
        if (i > m) {
        if (Ma.find(d) == Ma.end()) Ma[d] = ++cnt;
        int index = Ma[d];
        //记录delta,由于可能存在多个相等的delta,开一个vector记下它是哪个集合(状态压缩)
        S[index].push_back(s);
        return ;
        }
        dfs1(i + 1, s, d);
        dfs1(i + 1, s | (1 << i), d + a[i]);
        dfs1(i + 1, s | (1 << i), d - a[i]);
    }
    
    void dfs2(int i, int s, int d) {
        if (i > n) {
        if (Ma.find(d) == Ma.end()) return ;
        int index = Ma[d];
        std::vector<int>::iterator it;
        //直接查询然后置他们的并集为真即可
        for (it = S[index].begin(); it != S[index].end(); ++it)
            ok[*it | s] = true;
        return ;
        }
        dfs2(i + 1, s, d);
        dfs2(i + 1, s | (1 << i), d + a[i]);
        dfs2(i + 1, s | (1 << i), d - a[i]);
    }
    
    int main () {
        read(n); m = n >> 1;
        for(int i = 1; i <= n; ++i) read(a[i]);
        dfs1(1, 0, 0);
        dfs2(m + 1, 0, 0);
        for(int i = (1 << (n + 1)) - 1; i >= 1; --i)
        ans += ok[i];
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    eclipse配置Tomcat The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
    解决掉你心中 js function与Function的关系的疑问
    英语 one day
    合并两个有序链表
    有效的括号
    探讨前后端分离
    菜鸡发现腾讯视频bug
    最长公共前缀
    字符串转整数
    回文数
  • 原文地址:https://www.cnblogs.com/water-mi/p/9798624.html
Copyright © 2011-2022 走看看