poj3977(折半枚举+二分查找)
题目链接:https://vjudge.net/problem/POJ-3977
题意:给一个大小<=35的集合,找一个非空子集合,使得子集合元素和的绝对值最小,如果有多个这样的集合,找元素个数最少的。
思路:显然,可以用折半搜索,分别枚举一半,最大是2的18次方,复杂度能够满足。因为集合非空,枚举时考虑只在前一半选和只在后一半选的情况。对于前一半后一半都选的情况,把前一半的结果存下来,排序,枚举后一半的时候在前一半里二分查找最合适的即可。
思路不难,实现有很多细节,最开始用dfs写得一直wa,改成二进制循环才A。
AC代码:
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std; typedef long long LL;
typedef pair<LL,int> PLI;
const LL inf1=1e17;
const int inf2=0x3f3f3f3f;
int n,m,cnt,ans2;
LL a[],ans1;
PLI b[];
map<LL,int> mp; LL absLL(LL x){
return x>=?x:-x;
} int main(){
while(scanf("%d",&n),n){
mp.clear();
cnt=;
ans1=inf1;
ans2=inf2;
for(int i=;i<=n;++i)
scanf("%lld",&a[i]);
m=n/;
for(int i=;i<(<<m);++i){
LL res1=;
int res2=;
for(int j=;j<m;++j)
if((i>>j)&){
res1+=a[j+];
++res2;
}
if(absLL(res1)<ans1){
ans1=absLL(res1),ans2=res2;
}
else if(absLL(res1)==ans1){
ans2=min(ans2,res2);
}
if(mp.count(res1)){
int tmp=mp[res1];
b[tmp].second=min(b[tmp].second,res2);
}
else{
b[++cnt].first=res1,b[cnt].second=res2;
mp[res1]=cnt;
}
}
sort(b+,b+cnt+);
for(int i=;i<(<<(n-m));++i){
LL res1=;
int res2=;
for(int j=;j<(n-m);++j)
if((i>>j)&){
res1+=a[j++m];
++res2;
}
if(absLL(res1)<ans1){
ans1=absLL(res1),ans2=res2;
}
else if(absLL(res1)==ans1){
ans2=min(ans2,res2);
}
LL tmp=-res1;
int l=,r=cnt,mid;
while(l<=r){
mid=(l+r)>>;
if(b[mid].first<=tmp) l=mid+;
else r=mid-;
}
if(r>){
if(absLL(b[r].first+res1)<ans1){
ans1=absLL(b[r].first+res1);
ans2=b[r].second+res2;
}
else if(absLL(b[r].first+res1)==ans1){
ans2=min(ans2,b[r].second+res2);
}
}
if(r+<=cnt){
if(absLL(b[r+].first+res1)<ans1){
ans1=absLL(b[r+].first+res1);
ans2=b[r+].second+res2;
}
else if(absLL(b[r+].first+res1)==ans1){
ans2=min(ans2,b[r+].second+res2);
}
}
}
printf("%lld %d\n",ans1,ans2);
}
return ;
}
poj3977(折半枚举+二分查找)的更多相关文章
- CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。
1514: Packs Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 61 Solved: 4[Submit][Status][Web Board] ...
- Subset POJ - 3977(折半枚举+二分查找)
题目描述 Given a list of N integers with absolute values no larger than 10 15, find a non empty subset o ...
- Subset---poj3977(折半枚举+二分查找)
题目链接:http://poj.org/problem?id=3977 给你n个数,找到一个子集,使得这个子集的和的绝对值是最小的,如果有多种情况,输出子集个数最少的: n<=35,|a[i]| ...
- POJ 2549 Sumsets(折半枚举+二分)
Sumsets Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11946 Accepted: 3299 Descript ...
- 【折半枚举+二分】POJ 3977 Subset
题目内容 Vjudge链接 给你\(n\)个数,求出这\(n\)个数的一个非空子集,使子集中的数加和的绝对值最小,在此基础上子集中元素的个数应最小. 输入格式 输入含多组数据,每组数据有两行,第一行是 ...
- POJ 3977 Subset(折半枚举+二分)
SubsetTime Limit: 30000MS Memory Limit: 65536KTotal Submissions: 6754 Accepted: 1277 D ...
- Codeforces H. Prime Gift(折半枚举二分)
题目描述: Prime Gift time limit per test 3.5 seconds memory limit per test 256 megabytes input standard ...
- POJ 2785 4 Values whose Sum is 0(折半枚举+二分)
4 Values whose Sum is 0 Time Limit: 15000MS Memory Limit: 228000K Total Submissions: 25675 Accep ...
- POJ 3977:Subset(折半枚举+二分)
[题目链接] http://poj.org/problem?id=3977 [题目大意] 在n个数(n<36)中选取一些数,使得其和的绝对值最小. [题解] 因为枚举所有数选或者不选,复杂度太高 ...
随机推荐
- [Luogu] 稳定婚姻
https://www.luogu.org/problemnew/show/1407 tarjan求一下强连通分量,然后判断一下两个人是否在同一强连通分量中 #include<iostream& ...
- ICP、MRR、BKA等特性
一.Index Condition Pushdown(ICP) Index Condition Pushdown (ICP)是 mysql 使用索引从表中检索行数据的一种优化方式,从mysql5.6开 ...
- codeforces392B
CF392B Tower of Hanoi 题意翻译 河内塔是一个众所周知的数学难题.它由三根杆和一些可以滑动到任何杆上的不同尺寸的圆盘组成.难题从一个整齐的杆中开始,按照尺寸从小到大的顺序排列,最小 ...
- cmake语法入门记录
刚刚开始学习ROS,打算入机器人的坑了,参考教材是<ROS及其人开发实践>胡春旭编著 机械工业出版社 华章科技出品.本来以为可以按照书上的步骤一步步来,但是,too young to si ...
- jinja2-模版继承
一 简要 简单的来说模板继承包含基本模板和子模板.其中基本模板里包含了你这个网站里的基本元素的基本骨架,但是里面有一些空的或者是不完善的块(block)需要用子模板来填充. 二 基本模版样例 这个模板 ...
- java课后实验性问题5
课后作业一:字符串加密 程序设计思想: 从键盘获取字符串,将字符串转为字符数组,将每个元素加事前协定的“key”,再转为字符串输出. 程序流程图: 源代码: import java.util.Scan ...
- xpath 轴定位表达方式
xpath的使用基本语法: 1.// 从根节点开始,查找对象是全文. 2./ 从当前标签的路径开始查找 3.text()获取当前路径下的文本 4.@+类名或者id名 查找类名或者id的名字 5. .一 ...
- 安装 PostgreSQL 时丢失 libintl-8.dll 解决方案
发表于 2013 年 11 月 13 日 修订于 2018 年 05 月 05 日 PostgreSQL 比 MySQL 有更多的高级特性,而且微信支付的数据库也是基于 PostgreSQL ...
- pip 安装的问题
安装 pip install mysql-python 报错: mysql_config: command not found 解决办法: yum install mysql-devel yum ...
- 三、Navicat将远程MySql数据库数据导入本地
1.安装本地的MySql.记住用户名和密码,这里以root,root为例. 2.打开Navicat,新建连接(连接),输入连接名,用户名,密码.确定,连接测试.这里连接名为luzhanshi.这样本地 ...