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.将集合中的元素分成两 ...
随机推荐
- loop
-- ------------------------loop---------------------------delimiter $DROP PROCEDURE IF EXISTS my_cou ...
- java之线程飞机大战制作
import java.awt.Graphics; import java.util.ArrayList; import javax.swing.JFrame; import javax.swing. ...
- latex学习
第一段代码 \documentclass{article} \usepackage{ctex} \begin{document} \section{文字} 特可爱模板 \section{数学} \[ ...
- C++面向对象类的实例题目五
题目描述: 编写一个程序,采用一个类求n!,并输出5!的值. 程序代码: #include<iostream> using namespace std; class CFactorial ...
- ROS Learning-015 learning_tf(编程) 编写一个监听器程序 (Python版)
ROS Indigo learning_tf-02 编写一个 监听器 程序 (Python版) 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 1 ...
- 【Boost】boost库中timer定时器 1
博客转载自:http://blog.csdn.net/liujiayu2/article/details/50384537 同步Timer asio中提供的timer名为deadline_timer, ...
- Bootstrap 组件之 List group
简介 List group 指列表.当然,Bootstrap 列表不局限于由 <ul> 和 <li> 标签构成的. Bootstrap 中一共三种列表的构成方式,这里 有一个例 ...
- window.location和window.location.href和document.location的关系
1,首先来区分window.location和window.location.href. window.location.href是一个字符串. 而window.location是一个对象,包含属性有 ...
- TCP/IP与套接字
以前我们讲过进程间通信,通过进程间通信可以实现同一台计算机上不同的进程之间通信. 通过网络编程可以实现在网络中的各个计算机之间的通信. 进程能够使用套接字实现和其他进程或者其他计算机通信. 同样的套接 ...
- 【Arcgis android】 离线编辑实现及一些代码段
Arcgis android 离线编辑实现及一些代码段 底图添加 private String path="file:///mnt/sdcard/data/chinasimple.tpk&q ...