SPOJ11469 Subset(折半枚举)
题意
给定一个集合,有多少个非空子集,能划分成和相等的两份。$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(折半枚举)的更多相关文章
- POJ 3977 Subset(折半枚举+二分)
SubsetTime Limit: 30000MS Memory Limit: 65536KTotal Submissions: 6754 Accepted: 1277 D ...
- POJ3977 Subset 折半枚举
题目大意是给定N个数的集合,从这个集合中找到一个非空子集,使得该子集元素和的绝对值最小.假设有多个答案,输出元素个数最少的那个. N最多为35,假设直接枚举显然是不行的. 可是假设我们将这些数分成两半 ...
- POJ 3977 - subset - 折半枚举
2017-08-01 21:45:19 writer:pprp 题目: • POJ 3977• 给定n个数,求一个子集(非空)• 使得子集内元素和的绝对值最小• n ≤ 35 AC代码如下:(难点:枚 ...
- poj 3977 Subset(折半枚举+二进制枚举+二分)
Subset Time Limit: 30000MS Memory Limit: 65536K Total Submissions: 5721 Accepted: 1083 Descripti ...
- Load Balancing 折半枚举大法好啊
Load Balancing 给出每个学生的学分. 将学生按学分分成四组,使得sigma (sumi-n/4)最小. 算法: 折半枚举 #include <iostrea ...
- CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。
1514: Packs Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 61 Solved: 4[Submit][Status][Web Board] ...
- NYOJ 1091 超大01背包(折半枚举)
这道题乍一看是普通的01背包,最最基础的,但是仔细一看数据,发现普通的根本没法做,仔细观察数组发现n比较小,利用这个特点将它划分为前半部分和后半部分这样就好了,当时在网上找题解,找不到,后来在挑战程序 ...
- Codeforces 888E - Maximum Subsequence(折半枚举(meet-in-the-middle))
888E - Maximum Subsequence 思路:折半枚举. 代码: #include<bits/stdc++.h> using namespace std; #define l ...
- Codeforces 912 E.Prime Gift (折半枚举、二分)
题目链接:Prime Gift 题意: 给出了n(1<=n<=16)个互不相同的质数pi(2<=pi<=100),现在要求第k大个约数全在所给质数集的数.(保证这个数不超过1e ...
- poj_3977 折半枚举
题目大意 给定N(N<=35)个数字,每个数字都<= 2^15. 其中一个或多个数字加和可以得到s,求出s的绝对值的最小值,并给出当s取绝对值最小值时,需要加和的数字的个数. 题目分析 需 ...
随机推荐
- log4net 性能测试
1.执行事务:20260 次 写日志: 耗时11.59分 不写日志: 耗时11.55分 异步日志: 耗时12.49分 (个人电脑,.net 线程池调用线程写日志可能比主线程直 ...
- 【POJ】2892 Tunnel Warfare
[算法]平衡树(treap) [题解]treap知识见数据结构 在POJ把语言从G++换成C++就过了……??? #include<cstdio> #include<algorith ...
- 【BZOJ】1699 [Usaco2007 Jan]Balanced Lineup排队
[算法]线段树 #include<cstdio> #include<cctype> #include<algorithm> using namespace std; ...
- MySQL增删改查之查询
(7)范围查询select * from car where price>40 and price<60 --查询价格在40-60之间的select * from car where ...
- 所有和Java中代理有关的知识点都在这了。
对于每一个Java开发来说,代理这个词或多或少都会听说过.你可能听到过的有代理模式.动态代理.反向代理等.那么,到底什么是代理,这么多代理又有什么区别呢.本文就来简要分析一下. 代理技术,其实不只是J ...
- D题 hdu 1412 {A} + {B}
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1412 {A} + {B} Time Limit: 10000/5000 MS (Java/Others ...
- 关于this问题
对于关键字this,其实很好理解,谁调用我就指向谁.下面举个例子说明: 其实这也是在学习闭包中的一个案例: var name = "The window"; var obj = { ...
- macaca安装失败的解决办法!
https://github.com/macacajs/macaca-android https://www.jianshu.com/p/76a5be6c1036
- [session篇]看源码学习session(一)
假如你是使用过或学习过PHP,你一定觉得很简单.session只不过是$_SESSION就可以搞得,这还不简单只是对一个key-value就能工作了.我觉得可以大多数的phper都是这样的,这是语言本 ...
- VM虚拟机,Linux系统安装tools过程遇到 what is the location of the “ifconfig” program
安装步骤: 复制到/mnt 解压文件 tar -zxvf VMwareTools-10.1.6-5214329.tar.gz 进入减压文件夹后安装 ./vmware-install.pl ... 一直 ...