Subset
Time Limit: 30000MS   Memory Limit: 65536K
Total Submissions: 3161   Accepted: 564

Description

Given a list of N integers with absolute values no larger than 1015, find a non empty subset of these numbers which minimizes the absolute value of the sum of its elements. In case there are multiple subsets, choose the one with fewer elements.

Input

The input contains multiple data sets, the first line of each data set contains N <= 35, the number of elements, the next line contains N numbers no larger than 1015 in absolute value and separated by a single space. The input is terminated with N = 0

Output

For each data set in the input print two integers, the minimum absolute sum and the number of elements in the optimal subset.

Sample Input

1
10
3
20 100 -100
0

Sample Output

10 1
0 2

Source

 
 
 
解析:折半枚举。N个元素的集合,子集有2N个,除去空集,有2N-1个子集。而N可达35,235-1这个数就很大了,即使给了30000ms,直接枚举也会超时,可以考虑折半枚举。把集合分为两部分,这样两个小集合元素规模至多为18,枚举量为218,在可以承受的范围内。这样就得到了两个可枚举的集合A和B,最终的结果来源于这三种情况:子集的元素只取自于A、子集的元素只取自于B、子集的元素取自A和B。对于子集的元素只取自于A、子集的元素只取自于B这两种情况,我们在枚举的时候不断更新就可以了。对于子集的元素取自A和B这种情况,我们在枚举B(假设得到的子集中所有元素的和为sum)时,最佳情况为在A中找到-sum,这样我们在二分查找时,在-sum附近进行更新即可。另外,POJ暂不支持64位的abs,自己写一个吧^_^
 
 
 
#include <cstdio>
#include <map>
#define ll long long
using namespace std; int n;
ll a[40]; ll ll_abs(ll x)
{
return x >= 0 ? x : -x;
} void solve()
{
map<ll, int> mp;
map<ll, int>::iterator it;
pair<ll, int> res(ll_abs(a[0]), 1); //初始化结果为第一个元素
for(int i = 1; i < 1<<(n/2); ++i){ //枚举区间为[1, 2^n),当i为0时,子集为空
ll sum = 0;
int num = 0;
for(int j = 0; j < n/2; ++j){ //按位枚举
if((i>>j)&1){
sum += a[j];
++num;
}
}
res = min(res, make_pair(ll_abs(sum), num)); //子集的元素只取自于A
it = mp.find(sum);
if(it != mp.end())
it->second = min(it->second, num);
else
mp[sum] = num;
}
for(int i = 1; i < 1<<(n-n/2); ++i){
ll sum = 0;
int num = 0;
for(int j = 0; j < n-n/2; ++j){
if((i>>j)&1){
sum += a[n/2+j];
++num;
}
}
res = min(res, make_pair(ll_abs(sum), num)); //子集的元素只取自于B
it = mp.lower_bound(-sum); //查找与-sum最相近的值
if(it != mp.end()) //可能在该位置
res = min(res, make_pair(ll_abs(it->first+sum), it->second+num));
if(it != mp.begin()){ //可能在该位置的前一个位置
--it;
res = min(res, make_pair(ll_abs(it->first+sum), it->second+num));
}
}
printf("%I64d %d\n", res.first, res.second);
} int main()
{
while(scanf("%d", &n), n){
for(int i = 0; i < n; ++i)
scanf("%I64d", &a[i]);
solve();
}
return 0;
}

  

  

POJ 3977 Subset的更多相关文章

  1. POJ 3977 - subset - 折半枚举

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

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

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

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

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

  4. 【折半枚举+二分】POJ 3977 Subset

    题目内容 Vjudge链接 给你\(n\)个数,求出这\(n\)个数的一个非空子集,使子集中的数加和的绝对值最小,在此基础上子集中元素的个数应最小. 输入格式 输入含多组数据,每组数据有两行,第一行是 ...

  5. [poj] 3977 Subset || 折半搜索MITM

    原题 给定N个整数组成的数列(N<=35),从中选出一个子集,使得这个子集的所有元素的值的和的绝对值最小,如果有多组数据满足的话,选择子集元素最少的那个. n<=35,所以双向dfs的O( ...

  6. POJ 3977 Subset | 折半搜索

    题目: 给出一个整数集合,求出非空子集中元素和绝对值最小是多少(元素个数尽量少) 题解: 分成两半 爆搜每一半,用map维护前一半的值 每搜出后一半的一个值就去map里找和他和绝对值最小的更新答案 # ...

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

    题意:有一个N(N <= 35)个数的集合,每个数的绝对值小于等于1015,找一个非空子集,使该子集中所有元素的和的绝对值最小,若有多个,则输出个数最小的那个. 分析: 1.将集合中的元素分成两 ...

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

    [题目链接] http://poj.org/problem?id=3977 [题目大意] 在n个数(n<36)中选取一些数,使得其和的绝对值最小. [题解] 因为枚举所有数选或者不选,复杂度太高 ...

  9. Subset POJ - 3977(折半枚举+二分查找)

    题目描述 Given a list of N integers with absolute values no larger than 10 15, find a non empty subset o ...

随机推荐

  1. PHP Zend Studio9.0怎么把代码搞成和服务器端的同步(就是直接在服务器端修改)

    Zend Studio 可以直接通过Remote System的方式直接连接服务器端的代码,就是可以直接修改服务器端的代码,不过修改的时间小心点,修改就会立即生效的. 选择Remote Systems ...

  2. REST和SOAP Web Service的区别比较

    本文转载自他人的博客,ArcGIS Server 推出了 对 SOAP 和 REST两种接口(用接口类型也许并不准确)类型的支持,本文非常清晰的比较了SOAP和Rest的区别联系! ///////// ...

  3. Jmeter 快速入门教程(二)--创建简单web测试

    [版权所有: whoistester.com & jmeter.cf] http://wenku.baidu.com/linkurl=9zc4VHe6vUUeMdDZPpNsRehkazZFw ...

  4. OPenGL中三维图形的矩阵变换

    对于二维的图形开发,拿简单的图片显示来说,我们主要的目的:就是在一块显示buffer中,不停的把每个像素进行着色,然后就可以绘制出来了.为了速度,很多其他的加速方法,但原理基本上就是这样了. 很直观, ...

  5. [hackerrank]John and GCD list

    https://www.hackerrank.com/contests/w8/challenges/john-and-gcd-list 简单题,GCD和LCM. #include <vector ...

  6. TCL语言笔记:TCL中的控制结构命令

    一.引言 控制结构允许程序根据不同的状态.条件和参数来选择不同的处理和执行路径,从而使代码具有更强的灵活性.健壮性和可读性. Tcl 提供了 if.if/else.if/elseif.foreach. ...

  7. C#基础练习(事件登陆案例)

    Form1的后台代码: namespace _08事件登陆案例 {     public partial class Form1 : Form     {         public Form1() ...

  8. linux系统启动级别

    linux运行级别 以管理员身份进入Linux,修改文件:/etc/inittab 找到"id:5:initdefault:"其中的5就是X-window,为默认的运行级别 lin ...

  9. redhat 7.2 配置yum源

    http://blog.csdn.net/wylfengyujiancheng/article/details/50418930

  10. iptables配置——NAT地址转换

    iptables nat 原理同filter表一样,nat表也有三条缺省的"链"(chains): PREROUTING:目的DNAT规则 把从外来的访问重定向到其他的机子上,比如 ...