题目

Given a list of N integers with absolute values no larger than \(10^{15}\), 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.

输入格式

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 10 15 in absolute value and separated by a single space. The input is terminated with N = 0

输出格式

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

样例输入

1
10
3
20 100 -100
0

样例输出

10 1
0 2

题解

我自己想的话,除了暴力没有别的办法,看了题解,照着打了一遍代码,才能理解这个解法

具体思想就是,全都暴力会超时,所以分成两半枚举,左半部分枚举完保存,右半部分枚举后在左半部分二分查询。

这算优化暴力吗,dalao们的暴力也和我的暴力不一样。。。

这个代码使用了不少STL也是一个学习STL的机会

代码

#include <algorithm>
#include <cstdio>
#include <map>
using namespace std;
#define abs(x) ((x) >= 0 ? (x) : -(x))
long long arr[40];
int main() {
int n;
while (scanf("%d", &n), n) {
for (int i = 0; i < n; i++) scanf("%lld", &arr[i]);
pair<long long, long long> ans(abs(arr[0]), 1);
map<long long, long long> m;
map<long long, long long>::iterator it;
int nl = n >> 1, nr = n - (n >> 1);
for (int i = 1; i < (1 << nl); i++) {
long long sum = 0, cnt = 0;
for (int j = 0; j < nl; j++) {
if ((i >> j) & 1) sum += arr[j], cnt++;
}
long long sum1 = abs(sum);
if (sum1 < ans.first || (sum1 == ans.first && cnt < ans.second)) ans = make_pair(sum1, cnt);
if (m[sum]) m[sum] = min(m[sum], cnt);
else m[sum] = cnt;
}
for (int i = 1; i < (1 << nr); i++) {
long long sum = 0, cnt = 0;
for (int j = 0; j < nr; j++)
if ((i >> j) & 1) sum += arr[j + nl], cnt++;
long long sum1 = abs(sum);
if (sum1 < ans.first || (sum1 == ans.first && cnt < ans.second)) ans = make_pair(sum1, cnt);
it = m.lower_bound(-sum);
if (it != m.end()) {
long long s = abs(it->first + sum), t = it->second + cnt;
if (s < ans.first || (s == ans.first && t < ans.second))
ans = make_pair(s, t);
}
if (it != m.begin()) {
it--;
long long s = abs(it->first + sum), t = it->second + cnt;
if (s < ans.first || (s == ans.first && t < ans.second))
ans = make_pair(s, t);
}
}
printf("%lld %lld\n", ans.first, ans.second);
}
return 0;
}

POJ 3977 题解的更多相关文章

  1. POJ 3977 - subset - 折半枚举

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

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

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

  3. POJ 3977 折半枚举

    链接: http://poj.org/problem?id=3977 题意: 给你n个数,n最大35,让你从中选几个数,不能选0个,使它们和的绝对值最小,如果有一样的,取个数最小的 思路: 子集个数共 ...

  4. POJ 3977 Subset

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

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

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

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

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

  7. POJ 3977 Subset | 折半搜索

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

  8. poj 3744 题解

    题目 题意: $ yyf $ 一开始在 $ 1 $ 号节点他要通过一条有 $ n $ 个地雷的道路,每次前进他有 $ p $ 的概率前进一步,有 $ 1-p $ 的概率前进两步,问他不领盒饭的概率. ...

  9. poj 3061 题解(尺取法|二分

    题意 $ T $ 组数据,每组数据给一个长度 $ N $ 的序列,要求一段连续的子序列的和大于 $ S $,问子序列最小长度为多少. 输入样例 2 10 15 5 1 3 5 10 7 4 9 2 8 ...

随机推荐

  1. HashMap源码解析(java1.8.0)

    1.1 背景知识 1.1.1 红黑树 二叉查找树可能因为多次插入新节点导致失去平衡,使得查找效率低,查找的复杂度甚至可能会出现线性的,为了解决因为新节点的插入而导致查找树不平衡,此时就出现了红黑树. ...

  2. 【PHP】如何将SESSION数据存放到Redis中

    在php中,SESSION的数据默认是存放到文件中,这样性能不仅不高,而且不利于扩展.在搭建集群后,默认存放到文件中就不适用了.所以,我们一般将SESSION自定义,让SESSION中的数据存放到 数 ...

  3. 【原创】Linux中断子系统(三)-softirq和tasklet

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  4. 附015.Kubernetes其他技巧

    一 优化镜像源 1.1 国内镜像源 global proxy in China format example dockerhub (docker.io) dockerhub.azk8s.cn dock ...

  5. view中显示部分区域

    在android中有时候要求只显示view的部分区域,这个时候就需要对当前的view进行剪裁的操作.在android中剪裁当前的view的有两种方法:一种是直接截取view,第二种是通过Outline ...

  6. Cookie 和 Session 关系详解

     什么是 Cookie 和 Session ? 什么是 Cookie HTTP Cookie(也叫 Web Cookie或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在 ...

  7. 通过el-tree 实现每次可选中一个节点方案(非checkbox)

    <el-tree v-if="orgDrawer" :data="orgTree" size="medium" ref="o ...

  8. Docker图形界面管理

    之前都是使用命令行进行Docker的管理,这里简单介绍一下Docker的图形界面管理.之所以说简单介绍,是因为在生产环境都是集群,很少使用图形界面管理单台Docker主机,所以就演示记录一下,在个人测 ...

  9. 微信小程序-Page生命周期

    QQ讨论群:785071190 微信小程序开发之前我们还需认识一下小程序页面的生命周期,丛"微信小程序-代码构成"一文中我们可以了解到小程序页面中有一个.js的文件,这篇博文我们来 ...

  10. Centos 7使用systemctl补全服务名称

    使用jsw将程序打包成服务后,发现不能使用service + 服务名前几个字母 + tab 快捷键补全服务名,但是tab键可以补全文件夹名,翻阅了各个文档后,最终还是找到了问题所在. 本人安装的是Ce ...