题意

给定一个集合,有多少个非空子集,能划分成和相等的两份。$n\leq 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\n", ans);
return 0;
}

SPOJ11469 Subset(折半枚举)的更多相关文章

  1. POJ 3977 Subset(折半枚举+二分)

    SubsetTime Limit: 30000MS        Memory Limit: 65536KTotal Submissions: 6754        Accepted: 1277 D ...

  2. POJ3977 Subset 折半枚举

    题目大意是给定N个数的集合,从这个集合中找到一个非空子集,使得该子集元素和的绝对值最小.假设有多个答案,输出元素个数最少的那个. N最多为35,假设直接枚举显然是不行的. 可是假设我们将这些数分成两半 ...

  3. POJ 3977 - subset - 折半枚举

    2017-08-01 21:45:19 writer:pprp 题目: • POJ 3977• 给定n个数,求一个子集(非空)• 使得子集内元素和的绝对值最小• n ≤ 35 AC代码如下:(难点:枚 ...

  4. poj 3977 Subset(折半枚举+二进制枚举+二分)

    Subset Time Limit: 30000MS   Memory Limit: 65536K Total Submissions: 5721   Accepted: 1083 Descripti ...

  5. Load Balancing 折半枚举大法好啊

    Load Balancing 给出每个学生的学分.   将学生按学分分成四组,使得sigma (sumi-n/4)最小.         算法:   折半枚举 #include <iostrea ...

  6. CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

    1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] ...

  7. NYOJ 1091 超大01背包(折半枚举)

    这道题乍一看是普通的01背包,最最基础的,但是仔细一看数据,发现普通的根本没法做,仔细观察数组发现n比较小,利用这个特点将它划分为前半部分和后半部分这样就好了,当时在网上找题解,找不到,后来在挑战程序 ...

  8. Codeforces 888E - Maximum Subsequence(折半枚举(meet-in-the-middle))

    888E - Maximum Subsequence 思路:折半枚举. 代码: #include<bits/stdc++.h> using namespace std; #define l ...

  9. Codeforces 912 E.Prime Gift (折半枚举、二分)

    题目链接:Prime Gift 题意: 给出了n(1<=n<=16)个互不相同的质数pi(2<=pi<=100),现在要求第k大个约数全在所给质数集的数.(保证这个数不超过1e ...

  10. poj_3977 折半枚举

    题目大意 给定N(N<=35)个数字,每个数字都<= 2^15. 其中一个或多个数字加和可以得到s,求出s的绝对值的最小值,并给出当s取绝对值最小值时,需要加和的数字的个数. 题目分析 需 ...

随机推荐

  1. cnn 卷积神经网络 人脸识别

    卷积网络博大精深,不同的网络模型,跑出来的结果是不一样,在不知道使用什么网络的情况下跑自己的数据集时,我建议最好去参考基于cnn的手写数字识别网络构建,在其基础上进行改进,对于一般测试数据集有很大的帮 ...

  2. C# 类内部添加索引器

    public class PersonTable : Indexer { public int xuhao { get; set; } public string name { get; set; } ...

  3. js_在原有的日期上添加天数输出添加后的日期

    开始编码工作也有段时间了,想想没有留下点什么,有点遗憾.学到的一些经验,写写,分享一下.也给自己整理一下. 今天分享一下,在原有的日期上添加天数输出添加后的日期.开始做的时候,简单的思路是,直接用ne ...

  4. 创建Fragment和传递数值

    下面在扩展一下创建Fragment和传递数值 如果我们不需要传递数值,那就直接可以在宿主activity中,跟平常一样创建fragment,但是如果我们需要传递数据的话,可以使用newInstance ...

  5. 分布式队列Celery

    Celery是什么? Celery 是一个由 Python 编写的简单.灵活.可靠的用来处理大量信息的分布式系统,它同时提供操作和维护分布式系统所需的工具. Celery 专注于实时任务处理,支持任务 ...

  6. python基础===如何优雅的写代码(转自网络)

    本文是Raymond Hettinger在2013年美国PyCon演讲的笔记(视频, 幻灯片). 示例代码和引用的语录都来自Raymond的演讲.这是我按我的理解整理出来的,希望你们理解起来跟我一样顺 ...

  7. Hadoop(hadoop,HBase)组件import到eclipse

    1.简介: 将源代码import到eclipse可以方便的阅读和修改源码. 2.环境说明: mac mvn工具(Apache Maven 3.3.3 ) 3.hadoop(CDH5.4.2) 1.进入 ...

  8. [ python ] 项目一:FTP程序

    声明: 该项目参考学习地址: http://www.cnblogs.com/lianzhilei/p/5869205.html , 感谢博主分享,如有侵权,立即删除. 作业:开发一个支持多用户在线的F ...

  9. python 基础习题

    1.8<<2等于? 8 ---> 1000 32 ---> 100000 -----------结果--- 32 2.通过内置函数计算5除以2的余数 print(dir()) ...

  10. Http请求加签、验证操作

    加签.验签的作用 常见的http请求交互过程中,请求参数通过url或者request body等形式传输.但是由于http请求的开放性,使得请求参数很容易被拦截篡改.因此,需要对请求参数进行加签,然后 ...