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的正方形,每个格子要么是黑色,要么是白色,当把一个格子的颜色改变(黑->白或者白->黑)时, ...
随机推荐
- C/C++文件指针偏移
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- PHP strip_tags() 函数的作用和用法
strip_tags()函数可以轻松实现从字符串中去除 HTML 和 PHP 标记. 使用方法: trip_tags ( string $str [, string $allowable_tags ] ...
- SpringInAction--自动化装配Bean(显示装配之xml配置)
Spring在配置时候有三种方案可选 1.在xml中进行显示配置 2.在java中进行显示配置 3.隐式的Bean发现机制和自动装配 今天学习的 第一种—— 在xml中进行显示配置 老规矩 先创建 C ...
- Python的集合框架
Python内置了四种集合框架(list.tuple.dict.set) list:list是一种有序的集合 list里面的元素的数据类型也可以不同,list元素也可以是另一个list In [28] ...
- Alt+Shift+R组合键,用来在一个java文件中批量的重命名变量。
myeclipse和eclipse集成编译软件,都提供了一个快捷键用来批量重命名变量:Alt+Shift+R组合键,用来在一个java文件中批量的重命名变量.扩展知识:如果想要重命名文件名,又不想手动 ...
- 【Spring实战】Spring容器初始化完成后执行初始化数据方法
一.背景知识及需求 在做WEB项目时,经常在项目第一次启动时利用WEB容器的监听.Servlet加载初始化等切入点为数据库准备数据,这些初始化数据是系统开始运行前必须的数据,例如权限组.系统选项.默认 ...
- keras模型可视化及解决'Failed to import pydot'问题
1.keras模型可视化 keras.utils.vis_utils模块提供了画出Keras模型的函数(利用graphviz) 该函数将画出模型结构图,并保存成图片: from keras.utils ...
- SPU - SKU - ARPU
商品和单品: 单品:汉语中的“个” 例如,iphone是一个单品,但是在淘宝上当很多商家同时出售这个产品的时候,iphone就是一个商品了 商品:淘宝叫item,京东叫product,商品特指与商家 ...
- Ubuntu12.04中Gvim无法固定到启动器的解决办法
sudo vim /usr/share/applications/gvim.desktop 修改Categories键值如下: Categories=Application;Development;
- erl_0021 erlang和java的内存模型比较(引用)
原文 http://deepinmind.iteye.com/blog/2030390 我读到一篇相当相当有趣的关于Erlang VM内存管理策略的文章.它是Jesper Wilhelmsson写的 ...