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. Spring整合CXF发布及调用WebService

    这几天终于把webService搞定,下面给大家分享一下发布webService和调用webService的方法 添加jar包 (官方下载地址:http://cxf.apache.org/downlo ...

  2. flash cc新建swc文件

  3. PostgreSQL copy命令使用记录

    上篇写到用pg_bulkload来导入数据,但是实际的环境是solaris,pg_bulkload还不支持,于是用copy的方式,下面附上脚本 -bash-4.1$ cat copy.sh #!/bi ...

  4. TeamView

    1.TeamView TeamViewer是一个能在任何防火墙和NAT代理的后台用于远程控制,桌面共享和文件传输的简单且快速的解决方案.为了连接到另一台计算机,只需要在两台计算机上同时运行 TeamV ...

  5. 跟着小程学微服务-Mock自动化系统的原理及实现

    一.前言 在之前的文章 http://blog.csdn.net/u013970991/article/details/54862772 中已经介绍了"自动化Mock系统0.9版本" ...

  6. swift metal ios8 关键字.

    swift metal ios8  关键字. 4000API. 无所谓谁打败谁吧. 行业内用户用的多 资源多 问题容易解决. 今年明显unity 火热程度非常. 然,万变不离其中. 对于游戏产品来说, ...

  7. Shell 关闭指定进程

    例如要关闭jupyter-notebook这个进程: - | 说明:管道符“|”用来隔开两个命令,管道符左边命令的输出会作为管道符右边命令的输入. “ps -ef” 查看所有进程 “grep -v g ...

  8. BD09坐标(百度坐标) WGS84(GPS坐标) GCJ02(国测局坐标) 的相互转换

    BD09坐标(百度坐标) WGS84(GPS坐标) GCJ02(国测局坐标) 的相互转换 http://www.cnphp6.com/archives/24822 by root ⋅ Leave a ...

  9. selenium-java,定位并操作frame和iframe内的元素

    因为frame和iframe的原因,在frame里的元素不能直接定位需要切到相应的frame才可以对元素进行操作,下面是涉及的方法 webDriver.switchTo().defaultConten ...

  10. 为iPhone 6设计自适应布局(iOS8)

    Apple从iOS 6加入了Auto Layout后开始就比较委婉的开始鼓励.建议开发者使用自适应布局,但是到目前为止,我感觉大多数开发者一直在回避这个问题,不管是不是由于历史原因造成的,至少他们在心 ...