poj 3977 子集
题意:在一个集合中找到一个非空子集使得这个子集元素和的绝对值尽量小,和绝对值相同时保证元素个数尽量小
分析:1.二分枚举的思想,先分成两个集合;
2.枚举其中一个集合中所有的子集并且存到数组中,并排序;
3.枚举另一个集合中所有的子集并且与第一个集合中的合适子集相加(可以通过二分查找在数组中找到最合
适的元素)
4.这个题特别坑的地方是不能用abs库函数,只能手写
AC代码:
#include<stdio.h>
#include<map>
#include<algorithm>
using namespace std;
#define ll long long
ll a[];
ll Abs(ll x)
{
return x<?-x:x;
}
int main( )
{
int n;
while(scanf("%d",&n)!=EOF)
{
if(n==)
break;
for(int i= ; i<n ; i++)
scanf("%lld",&a[i]);
int n2=n/;
pair<ll,int> ans(Abs(a[]),);
map<ll,int>M;
map<ll,int>::iterator it;
for(int i= ; i<<<n2 ; i++)
{
ll sum=;int cnt=;
for(int j= ; j<n2 ; j++)
{
if(i>>j&)
{
sum+=a[j];
cnt++;
}
}
ans = min(ans,make_pair(Abs(sum),cnt));
if(M[sum])
M[sum]=min(M[sum],cnt);
else
M[sum]=cnt;
}
for(int i= ; i<<<(n-n2) ; i++)
{
ll sum=;int cnt=;
for(int j= ; j<n-n2 ; j++)
{
if(i>>j&)
{
sum+=a[j+n2];
cnt++;
} }
ans=min(ans,make_pair(Abs(sum),cnt));
it = M.lower_bound(-sum);
if(it != M.end())
ans = min(ans,make_pair(Abs(sum+it->first),cnt+it->second));
if(it != M.begin())
{
it--;
ans = min(ans,make_pair(Abs(sum+it->first),cnt+it->second));
} }
printf("%lld %d\n",ans.first,ans.second);
}
return ; }
带解析
#include <iostream>
#include <algorithm>
#include <limits>
#include <map>
using namespace std;
typedef long long LL;
#define MAX_N 36
LL number[MAX_N]; LL ll_abs(const LL& x) // damn it! error C3861: 'llabs': identifier not found
{
return x >= ? x : -x;
} ///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int N;
while (cin >> N && N)
{
for (int i = ; i < N; ++i)
{
cin >> number[i];
}
map<LL, int> dp; // sum的值<->集合元素个数,这里不是绝对值
pair<LL, int> result(ll_abs(number[]), ); // 最优解
for (int i = ; i < << (N / ); ++i) // 枚举前 N / 2
{
LL sum = ;
int num = ;
for (int j = ; j < N / ; ++j)
{
if ((i >> j) & )
{
sum += number[j];
++num;
}
}
if (num == )
{
continue;
}
result = min(result, make_pair(ll_abs(sum), num));
map<LL, int>::iterator it = dp.find(sum);
if (it != dp.end())
{
it->second = min(it->second, num);
}
else
{
dp[sum] = num;
}
} for (int i = ; i < << (N - N / ); ++i) // 枚举剩下的
{
LL sum = ;
int num = ;
for (int j = ; j < N - N / ; ++j)
{
if ((i >> j) & )
{
sum += number[N / + j];
++num;
}
}
if (num == )
{
continue;
}
result = min(result, make_pair(ll_abs(sum), num));
// 找寻跟-sum最相近的结果
map<LL, int>::iterator it = dp.lower_bound(-sum); // 返回大于或等于-sum的第一个元素位置
if (it != dp.end())
{// 可能是该位置
result = min(result, make_pair(ll_abs(sum + it->first), num + it->second));
}
if (it != dp.begin())
{// 或比该元素小一点点的
--it;
result = min(result, make_pair(ll_abs(sum + it->first), num + it->second));
}
}
cout << ll_abs(result.first) << ' ' << result.second << endl;
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
system("out.txt");
#endif
return ;
}
poj 3977 子集的更多相关文章
- POJ 3977 - subset - 折半枚举
2017-08-01 21:45:19 writer:pprp 题目: • POJ 3977• 给定n个数,求一个子集(非空)• 使得子集内元素和的绝对值最小• n ≤ 35 AC代码如下:(难点:枚 ...
- POJ 3977 折半枚举
链接: http://poj.org/problem?id=3977 题意: 给你n个数,n最大35,让你从中选几个数,不能选0个,使它们和的绝对值最小,如果有一样的,取个数最小的 思路: 子集个数共 ...
- POJ 3977:Subset(折半枚举+二分)
[题目链接] http://poj.org/problem?id=3977 [题目大意] 在n个数(n<36)中选取一些数,使得其和的绝对值最小. [题解] 因为枚举所有数选或者不选,复杂度太高 ...
- POJ 3977 Subset
Subset Time Limit: 30000MS Memory Limit: 65536K Total Submissions: 3161 Accepted: 564 Descriptio ...
- poj 3977 Subset(折半枚举+二进制枚举+二分)
Subset Time Limit: 30000MS Memory Limit: 65536K Total Submissions: 5721 Accepted: 1083 Descripti ...
- 【折半枚举+二分】POJ 3977 Subset
题目内容 Vjudge链接 给你\(n\)个数,求出这\(n\)个数的一个非空子集,使子集中的数加和的绝对值最小,在此基础上子集中元素的个数应最小. 输入格式 输入含多组数据,每组数据有两行,第一行是 ...
- 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(二分+折半枚举)
题意:有一个N(N <= 35)个数的集合,每个数的绝对值小于等于1015,找一个非空子集,使该子集中所有元素的和的绝对值最小,若有多个,则输出个数最小的那个. 分析: 1.将集合中的元素分成两 ...
随机推荐
- hadoop job -kill 与 yarn application -kii(作业卡了或作业重复提交或MapReduce任务运行到running job卡住)
问题详情 解决办法 [hadoop@master ~]$ hadoop job -kill job_1493782088693_0001 DEPRECATED: Use of this script ...
- ms project展开和折叠任务
1.视图——大纲——显示子任务 2.视图——大纲——隐藏子任务
- Solr搜索的排序打分规则探讨
使用Solr搭建搜索引擎很容易,但是如何制定合理的打分规则(boost)做排序却是一个很头痛的事情.Solr本身的排序打分规则是继承自Lucene的文本相关度的打分即boost,这一套算法对于通用的提 ...
- 详解CSS盒模型(转)
详解CSS盒模型 阅读目录 一些基本概念 盒模型 原文地址:http://luopq.com/2015/10/26/CSS-Box-Model/ 本文主要是学习CSS盒模型的笔记,总结了一些基本概 ...
- Ubuntu重启关机命令使用
如果你想保持当前用户的登录而且使用root用户执行命令 可以输入:su root,输入密码 可以运行,shutdown 命令 重启命令: 1.reboot 2.shutdown -r now 立刻重启 ...
- p3163 [CQOI2014]危桥
传送门 分析 代码 #include<iostream> #include<cstdio> #include<cstring> #include<string ...
- [译]Javascript中的函数
本文翻译youtube上的up主kudvenkat的javascript tutorial播放单 源地址在此: https://www.youtube.com/watch?v=PMsVM7rjupU& ...
- C++11新标准:nullptr关键字
一.nullptr的意义 1.NULL在C中的定义 #define NULL (void*)0 2.NULL在C++中的定义 #ifndef NULL #ifdef __cplusplus #defi ...
- C++轮子队-第六周--事后分析
C++轮子队 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 实现2048+俄罗斯方块结合的小游戏,定义的比较清楚,典型用户也很清晰,提供给那些对该类游 ...
- jquery ajax 分页
<script src="../Js/jQuery/jquery-1.8.2.min.js" type="text/javascript">< ...