poj 3977 Subset(折半枚举+二进制枚举+二分)
Time Limit: 30000MS | Memory Limit: 65536K | |
Total Submissions: 5721 | Accepted: 1083 |
Description
Input
Output
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(折半枚举+二进制枚举+二分)的更多相关文章
- POJ 3977 - subset - 折半枚举
2017-08-01 21:45:19 writer:pprp 题目: • POJ 3977• 给定n个数,求一个子集(非空)• 使得子集内元素和的绝对值最小• n ≤ 35 AC代码如下:(难点:枚 ...
- POJ 3977 Subset(折半枚举+二分)
SubsetTime Limit: 30000MS Memory Limit: 65536KTotal Submissions: 6754 Accepted: 1277 D ...
- [poj] 3977 Subset || 折半搜索MITM
原题 给定N个整数组成的数列(N<=35),从中选出一个子集,使得这个子集的所有元素的值的和的绝对值最小,如果有多组数据满足的话,选择子集元素最少的那个. n<=35,所以双向dfs的O( ...
- POJ 3977 Subset | 折半搜索
题目: 给出一个整数集合,求出非空子集中元素和绝对值最小是多少(元素个数尽量少) 题解: 分成两半 爆搜每一半,用map维护前一半的值 每搜出后一半的一个值就去map里找和他和绝对值最小的更新答案 # ...
- POJ.3279 Fliptile (搜索+二进制枚举+开关问题)
POJ.3279 Fliptile (搜索+二进制枚举+开关问题) 题意分析 题意大概就是给出一个map,由01组成,每次可以选取按其中某一个位置,按此位置之后,此位置及其直接相连(上下左右)的位置( ...
- POJ - 3977 Subset(二分+折半枚举)
题意:有一个N(N <= 35)个数的集合,每个数的绝对值小于等于1015,找一个非空子集,使该子集中所有元素的和的绝对值最小,若有多个,则输出个数最小的那个. 分析: 1.将集合中的元素分成两 ...
- POJ 3279 Fliptile(反转 +二进制枚举)
Fliptile Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 13631 Accepted: 5027 Descrip ...
- 【折半枚举+二分】POJ 3977 Subset
题目内容 Vjudge链接 给你\(n\)个数,求出这\(n\)个数的一个非空子集,使子集中的数加和的绝对值最小,在此基础上子集中元素的个数应最小. 输入格式 输入含多组数据,每组数据有两行,第一行是 ...
- POJ 1753 Flip Game(二进制枚举)
题目地址链接:http://poj.org/problem?id=1753 题目大意: 有4*4的正方形,每个格子要么是黑色,要么是白色,当把一个格子的颜色改变(黑->白或者白->黑)时, ...
随机推荐
- tsl/ssl 证书制作记录
生成自签名证书 生成服务端秘钥 $ openssl genrsa -out server.key 1024 生成证书请求文件 编写配置文件openssl.cnf $ vi openssl.cnf [r ...
- python中pickle模块与base64模块的使用
pickle模块的使用 pickle模块是python的标准模块,提供了对于python数据的序列化操作,可以将数据转换为bytes类型,其序列化速度比json模块要高. pickle.dumps() ...
- 解决WIFI驱动RTL8188无法在rk3168平板Android4.2启动wifi的问题
http://blog.csdn.net/morixinguan/article/details/75228335 上一篇博文能把ko编译出来,非常兴奋的想,这一定是没问题了,结果删除原先的ko后,加 ...
- .NET 方法回调
使用 AsyncCallback 委托在一个单独的线程中处理异步操作的结果. AsyncCallback 委托表示在异步操作完成时调用的回调方法. 回调方法采用 IAsyncResult 参数,该参数 ...
- Python源码分析(二) - List对象
python中的高级特性之一就是内置了list,dict等.今天就先围绕列表(List)进行源码分析. Python中的List对象(PyListObject) Python中的的PyListObje ...
- 【剑指offer】04A二维数组中的查找,C++实现
1.题目 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数数组和一个整数,判断数组中是否含有该整数. 2.思路 首先选取数 ...
- IOS SEL (@selector) 原理及使用总结(一)
SEL 类成员方法的指针 可以理解 @selector()就是取类方法的编号,他的行为基本可以等同C语言的中函数指针,只不过C语言中,可以把函数名直接赋给一个函数指针,而Object-C的类不能直接应 ...
- Hbase rowkey热点问题
当处理由连续事件得到的数据时,即时间上连续的数据.这些数据可能来自于某个传感器网络.证券交易或者一个监控系统.它们显著的特点就是rowkey中含有事件发生时间.带来的一个问题便是HBase对于row的 ...
- hadoop常见错误总结三
问题导读:1.... could only be replicated to 0 nodes, instead of 1 ...可能的原因是什么?2.Error: java.lang.NullPoin ...
- java集成WebSocket向指定用户发送消息
一.WebSocket简单介绍 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通 ...