题目内容

Vjudge链接

给你\(n\)个数,求出这\(n\)个数的一个非空子集,使子集中的数加和的绝对值最小,在此基础上子集中元素的个数应最小。

输入格式

输入含多组数据,每组数据有两行,第一行是元素组合\(n\)(若\(n\)为0表示输入结束),第二行有\(n\)个数,表示要给出的\(n\)个数。

数据范围

\(n\le 35\)

输出格式

每组数据输出一行两个数中间用空格隔开,表示最小的绝对值和该子集的元素个数。

样例输入

1

10

3

20 100 -100

0

样例输出

10 1

0 2

思路

在学必修一的第一节课我们就知道有\(n\)个数的集合的非空子集有\(2^n-1\)个,因此此题直接枚举的话大小回到\(2^{35}-1\),显然出题人没有这么好心。

这里用到一种思想叫做对半枚举。可以想到\(2^{17}-1=131071\),比较优秀的,那么就开始对半枚举就好了。将\(n\)的数分为前\(\frac{n}{2}\)和后\(\frac{n}{2}\)进行枚举。同时可以结合二分查找。

如果是一个空集加上一个非空,那么得到的也是非空集合,当然如果两个空集加在一起肯定也还是空集。

注意下边界。

代码

#include <cstdio>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll; ll Abs(ll x){//据说POJ不支持abs函数?
return x > 0 ? x : -x;
} int n;
ll a[40];
int main(){
while (scanf("%d",&n)&&n!=0){
for (int i=1;i<=n;++i)
scanf("%d",a+i);
map<ll,int> g;//一开始想用结构体结果发现结构体不能用lower_bound
ll ans=Abs(a[1]);
int len=n; for (int i=1;i<(1<<(n/2));++i){
ll sum=0;
int j=i,cnt=0,pos=1;
while(j&&pos<=n/2){
if (j&1){
sum+=a[pos];
cnt++;
}
j>>= 1;
pos++;
}
if (Abs(sum)<ans){
ans=Abs(sum);
len=cnt;
}
else if(Abs(sum)==ans){
len=min(len, cnt);
} if(g[sum])
g[sum]=min(g[sum], cnt);
else
g[sum]=cnt;
} for (int i=1;i<(1<<(n-n/2));++i){
ll sum=0;
int cnt=0,pos=1,j=i;
while (j&&pos+n/2<= n){
if (j&1){
sum+= a[pos+n/2];
cnt++;
}
j>>= 1;
pos++;
} if(Abs(sum) < ans){
ans=Abs(sum);
len=cnt;
}
else if(Abs(sum)==ans){
len=min(len,cnt);
} map<ll,int>::iterator it=g.lower_bound(-sum);//迭代器都要忘光了orz if(it!=g.end()){
if(Abs(sum+it->first)<ans){
ans=Abs(sum+it->first);
len=cnt+it->second;
}
else if(Abs(sum+it->first)==ans){
len=min(len,cnt+it->second);
}
} if (it!=g.begin()){
it--;
if(Abs(sum+it->first)<ans){
ans=Abs(sum+it->first);
len=cnt+it->second;
}
else if(Abs(sum+it->first)==ans){
len=min(len,cnt+it->second);
}
}
} scanf("%d %d\n",Abs(ans),len);
}
return 0;
}

代码启发

https://www.jianshu.com/p/27eefa7b990e

膜一下dalao的玛丽

【折半枚举+二分】POJ 3977 Subset的更多相关文章

  1. CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

    1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] ...

  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 - 折半枚举

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

  5. POJ 3977 Subset

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

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

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

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

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

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

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

  9. POJ 2549 Sumsets(折半枚举+二分)

    Sumsets Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11946   Accepted: 3299 Descript ...

随机推荐

  1. [LeetCode]1083. 销售分析 II(Mysql,having+if)

    题目 编写一个 SQL 查询,查询购买了 S8 手机却没有购买 iPhone 的买家. 题解 使用having + sum+if,而不是自查询. 代码 # Write your MySQL query ...

  2. JVM关于GC的日志分析

    通过阅读GC日志,我们可以了解Java虛拟机内存分配与回收策略.内存分配与垃圾回收的参数列表 一XX: +PrintGC 输出Gc日志.类似: 一verbose:gc 一XX: +PrintGCDet ...

  3. Github上如何添加 LICENSE 文件?

    什么是开源软件? 开源软件是所有人都可以修改和补充的软件,因为开源软件的 license 协议允许这样做. Git版本控制系统就是开源的软件. 实际上开源软件的一个重要组成部分就是添加 license ...

  4. 分布式系统监视zabbix讲解三之用户和用户组

    概述 Zabbix 中的所有用户都通过 Web 前端去访问 Zabbix 应用程序.并为每个用户分配唯一的登陆名和密码. 所有用户的密码都被加密并储存于 Zabbix 数据库中.用户不能使用其用户名和 ...

  5. 实验 3:Mininet 实验——测量路径的损耗率

    实验目的 在实验 2 的基础上进一步熟悉 Mininet 自定义拓扑脚本,以及与损耗率相关的设 定:初步了解 Mininet 安装时自带的 POX 控制器脚本编写,测试路径损耗率. 实验任务 h0 向 ...

  6. 修改python包pip下载国内源

    第一种方式- pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ 附国内常用镜像源:阿里云:https:// ...

  7. python-面向过程面向对象和栈的实现

    0x01 大纲 面向过程 函数 参数传递 返回 面向对象 类 栈的数据结构实现 0x02 例子 def add(a,b): return a+b if __name__ == '__main__': ...

  8. kafka学习(二)kafka工作流程分析

    一.发送数据 follower的同步流程 PS:Producer在写入数据的时候永远的找leader,不会直接将数据写入follower PS:消息写入leader后,follower是主动的去lea ...

  9. Spring Boot学习(二)搭建一个简易的Spring Boot工程

    第一步:新建项目 新建一个SpringBoot工程 修改项目信息 勾选项目依赖和工具 选择好项目的位置,点击[Finish] 第二步:项目结构分析 新建好项目之后的结构如下图所示,少了很多配置文件: ...

  10. Python-字符编码-Unicode UTF-8

    什么是字符编码? --世界上有很多国家,每个国家都有自己独特的语言,所以在计算机普及的当今世界, 每个国家都有自己的字符编码,本国的软件运行在其他国家的机器上,会出现乱码, 有utf-8,gbk等各种 ...