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

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(n<=35)个数的数组,让你在数组中选出一个非空子集,使其元素和的绝对值最小,输出子集元素的个数以及元素和的绝对值,若两个子集元素和相等,输出元素个数小的那个。

思路:如果直接暴力枚举,复杂度O(2^n),n为35时会超时,故可以考虑折半枚举,利用二进制将和以及元素个数存在两个结构体数组中,先预判两个结构体是否满足题意,再将其中一个元素和取相反数后排序,因为总元素和越接近零越好,再二分查找即可,用lower_bound时考虑查找到的下标和他前一个下标,比较元素和以及元素个数,不断更新即可。

详见代码注释

poj的long long abs要自己写

 #include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct Z
{
long long int x;
int y;
bool operator < (const Z& b)const
{
if (x != b.x)
return x < b.x;
return y<b.y; }
}a[], b[]; long long int c[]; long long int abs1(long long int x)
{
if (x<)
return -x;
return x;
} int main()
{
int n;
int i,j;
while (cin >> n && n)
{
for (i = ; i < ; i++)
{
a[i].x = a[i].y = b[i].x = b[i].y = ;
}
long long sum = 1e17;
int ans = ;
for (i = ; i < n; i++)
{
cin >> c[i];
}
int n1 = n / ;
for (i = ; i < ( << n1); i++)//二进制枚举一半,共2的n1次方种
{
for (j = ; j < n1; j++)
{
if (i >> j& && (i != || j != ))//这一半中的所有情况列出来
{
a[i - ].x+= c[j];
a[i - ].y++;//记录这个数含有几个元素
}
}
}
int n2 = n - n1;
for (i = ; i < ( << n2); i++)//同理初始化
{
for (j = ; j < n2; j++)
{
if (i >> j & && (i != || j != ))
{
b[i - ].x += c[j + n1];
b[i - ].y++;
}
}
}
//对这两半单独检查更新最小和sum和最小元素数ans
for (i = ; i < ( << n1) - ; i++)//?
{
if (abs1(a[i].x) < sum)
{
sum = abs1(a[i].x);
ans = a[i].y;
}
else if (abs1(a[i].x) == sum && a[i].y < ans)
{
ans=a[i].y;
sum = abs1(a[i].x);
}
} for (i = ; i<( << n1) - ; i++)//前半部分变为相反数
a[i].x = -a[i].x;
for (i = ; i<( << n2) - ; i++) //另一半检查
{
if (abs1(b[i].x)<sum)
{
sum = abs1(b[i].x);
ans = b[i].y;
}
else if (abs1(b[i].x) == sum && b[i].y<ans)
{
ans = b[i].y;
sum = abs1(b[i].x);
}
} sort(a, a + ( << n1) - );
sort(b, b + ( << n2) - ); for (i = ; i < ( << n1)-; i++)//两半合起来检查
{
int t = lower_bound(b, b + ( << n2) - , a[i])- b;//t是序号
if (t > )//查看该序号周围的数
{
if (abs1(b[t - ].x - a[i].x) < sum)//和可以更小
{
sum = abs1(b[t - ].x - a[i].x);//更新最小绝对值和
ans = b[t - ].y + a[i].y;//更新元素个数
}
else if (abs1(b[t - ].x - a[i].x) == sum && b[t - ].y + a[i].y < ans)//元素个数可以更小
{
sum = abs1(b[t - ].x - a[i].x);
ans = b[t - ].y + a[i].y;
}
}
if (t < ( << n2) - )
{
if (abs1(b[t].x - a[i].x) < sum)
{
sum = abs1(b[t].x - a[i].x);
ans = b[t].y + a[i].y;
}
else if (abs1(b[t].x - a[i].x) == sum && b[t].y + a[i].y<ans)
{
sum = abs1(b[t].x - a[i].x);
ans = b[t].y + a[i].y;
}
}
}
cout << sum << " " << ans << endl;
}
return ;
}

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(折半枚举+二分)

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

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

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

  4. POJ 3977 Subset | 折半搜索

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

  5. POJ.3279 Fliptile (搜索+二进制枚举+开关问题)

    POJ.3279 Fliptile (搜索+二进制枚举+开关问题) 题意分析 题意大概就是给出一个map,由01组成,每次可以选取按其中某一个位置,按此位置之后,此位置及其直接相连(上下左右)的位置( ...

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

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

  7. POJ 3279 Fliptile(反转 +二进制枚举)

    Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 13631   Accepted: 5027 Descrip ...

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

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

  9. POJ 1753 Flip Game(二进制枚举)

    题目地址链接:http://poj.org/problem?id=1753 题目大意: 有4*4的正方形,每个格子要么是黑色,要么是白色,当把一个格子的颜色改变(黑->白或者白->黑)时, ...

随机推荐

  1. CentOS7 开通特定防火墙端口

    >>> 开启端口 firewall-cmd --zone=public --add-port=/tcp --permanent  命令含义: --zone #作用域 --add-po ...

  2. APUE学习笔记——10.可靠信号与不可靠信号

    首先说明:现在大部分Unix系系统如Linux都已经实现可靠信号. 1~31信号与SIGRTMIN-SIGRTMAX之间并不是可靠信号与不可靠信号的区别,在大多数系统下他们都是可靠信号. 只不过: 1 ...

  3. 关于block和inline元素的float

    CSS float 浮动属性 本篇主要介绍float属性:定义元素朝哪个方向浮动. 目录 1. 页面布局方式:介绍文档流.浮动层以及float属性. 2. float:left :介绍float为 l ...

  4. 海思arm平台AAC音频转码cpu占用高、效率低的问题解决

    问题背景 目前市面上的大部分IPC摄像机音频输出基本都是G711.G726编码格式,而在类似于<基于EasyNVR实现RTSP/Onvif监控摄像头Web无插件化直播监控>这种业务中,都是 ...

  5. 怎么解决安装SqlServer2008总是提示Restart computer as failed

    安装SqlServer2008总是提示Restart computer as failed,重启电脑依然报这个錯.解决办法是在cmd窗口中使用命令setup.exe /SkipRules=Reboot ...

  6. confd与etcd的使用

    Add keys This guide assumes you have a working etcd, or consul server up and running and the ability ...

  7. git版本管理工具的使用

    Git的一些资料 --关于git的介绍就此忽略了--- Git官网http://git-scm.com/ Visual Studio Tools for Git下载地址https://visualst ...

  8. 自回归模型(AR )

    2017/7/2 19:24:15 自回归模型(Autoregressive Model,简称 AR 模型)是最常见的平稳时间序列模型之一.接下将介绍 AR 模型的定义.统计性质.建模过程.预测及应用 ...

  9. java并发--CountDownLatch、CyclicBarrier和Semaphore

    在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下 ...

  10. CF1117A Best Subsegment

    CF1117A Best Subsegment 乍一看好像很难,仔细想一下发现就是弱智题... 任意一段平均数显然不会超过最大的数,若只取最大数即可达到平均数为最大数. 于是只用取最长的一段连续的最大 ...