题目

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. Oracle 11g RAC之HAIP相关问题总结

    1 文档概要 2 禁用/启用HAIP 2.1 禁用/启用HAIP资源 2.2 修改ASM资源的依赖关系 3 修改cluster_interconnects参数 3.1 使用grid用户修改ASM实例的 ...

  2. @Autowired 注解详解

    前言 我们平时使用 Spring 时,想要 依赖注入 时使用最多的是 @Autowired 注解了,本文主要讲解 Spring 是如何处理该注解并实现 依赖注入 的功能的. 正文 首先我们看一个测试用 ...

  3. Spyder汉化教程

    汉化包下载地址:https://www.lizenghai.com/archives/523.html 1.解压汉化包 2. 3.1.运行汉化补丁PS C:\WINDOWS\system32> ...

  4. CentOS 7 源码编译安装PostgreSQL 9.5

    下载 在postgresql的官方即可找到源码文件目录,地址如下:https://www.postgresql.org/ftp/source/,在下载列表中根据需求选择版本,进入子目录后,可以看到文件 ...

  5. (一)JDK安装和使用eclipse输出hello world

    目录 一.jdk安装(推荐使用压缩包安装) 二.使用eclipse输出hello world 一.jdk安装(推荐使用压缩包安装) 1.压缩包安装的优点:若可能同时使用多个jdk版本,切换jdk时只需 ...

  6. VMWare虚拟机开启时显示模块“Disk”启动失败的解决方案

    找到虚拟机所在的目录, 将 .vmx文件打开 将文件vmci0.present = "TRUE"改为 vmci0.present = "FALSE" 删除以.l ...

  7. (六)POI-操作Excel的poi的字体设置

    原文链接:https://blog.csdn.net/class157/article/details/92817286 package com.java.poi; import org.apache ...

  8. fork,vfork和clone底层实现

    分类: LINUX2011-10-13 09:33 1116人阅读 评论(0) 收藏 举报 structdstsignalthreadnulldomain fork,vfork,clone都是linu ...

  9. 小师妹学JVM之:JIT中的LogCompilation

    目录 简介 LogCompilation简介 LogCompilation的使用 解析LogCompilation文件 总结 简介 我们知道在JVM中为了加快编译速度,引入了JIT即时编译的功能.那么 ...

  10. ThinkPHP6 上传图片代码demo

    本文展示了ThinkPHP6 上传图片代码demo, 代码亲测可用. HTML部分代码 <tr> <th class="font-size-sm" style=& ...