题目

题意:在一个集合中找到一个非空子集使得这个子集元素和的绝对值尽量小,和绝对值相同时保证元素个数尽量小

分析: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 子集的更多相关文章

  1. POJ 3977 - subset - 折半枚举

    2017-08-01 21:45:19 writer:pprp 题目: • POJ 3977• 给定n个数,求一个子集(非空)• 使得子集内元素和的绝对值最小• n ≤ 35 AC代码如下:(难点:枚 ...

  2. POJ 3977 折半枚举

    链接: http://poj.org/problem?id=3977 题意: 给你n个数,n最大35,让你从中选几个数,不能选0个,使它们和的绝对值最小,如果有一样的,取个数最小的 思路: 子集个数共 ...

  3. POJ 3977:Subset(折半枚举+二分)

    [题目链接] http://poj.org/problem?id=3977 [题目大意] 在n个数(n<36)中选取一些数,使得其和的绝对值最小. [题解] 因为枚举所有数选或者不选,复杂度太高 ...

  4. POJ 3977 Subset

    Subset Time Limit: 30000MS   Memory Limit: 65536K Total Submissions: 3161   Accepted: 564 Descriptio ...

  5. poj 3977 Subset(折半枚举+二进制枚举+二分)

    Subset Time Limit: 30000MS   Memory Limit: 65536K Total Submissions: 5721   Accepted: 1083 Descripti ...

  6. 【折半枚举+二分】POJ 3977 Subset

    题目内容 Vjudge链接 给你\(n\)个数,求出这\(n\)个数的一个非空子集,使子集中的数加和的绝对值最小,在此基础上子集中元素的个数应最小. 输入格式 输入含多组数据,每组数据有两行,第一行是 ...

  7. POJ 3977 Subset(折半枚举+二分)

    SubsetTime Limit: 30000MS        Memory Limit: 65536KTotal Submissions: 6754        Accepted: 1277 D ...

  8. [poj] 3977 Subset || 折半搜索MITM

    原题 给定N个整数组成的数列(N<=35),从中选出一个子集,使得这个子集的所有元素的值的和的绝对值最小,如果有多组数据满足的话,选择子集元素最少的那个. n<=35,所以双向dfs的O( ...

  9. POJ - 3977 Subset(二分+折半枚举)

    题意:有一个N(N <= 35)个数的集合,每个数的绝对值小于等于1015,找一个非空子集,使该子集中所有元素的和的绝对值最小,若有多个,则输出个数最小的那个. 分析: 1.将集合中的元素分成两 ...

随机推荐

  1. close、flush、read、readline、seek、tell、truncate、write的使用

    1.close关闭文件 f1= open("ha.log","r+",encoding="utf-8") data = f1.read() ...

  2. 使用Java建立聊天客户端

    ---------------siwuxie095                             关于 聊天服务器,详见本人博客的分类:来一杯Java, 里面的 使用ServerSocket ...

  3. 【转】nginx+memcached构建页面缓存应用

    如需转载请注明出处: http://www.ttlsa.com/html/2418.html nginx的memcached_module模块可以直接从memcached服务器中读取内容后输出,后续的 ...

  4. c语言学习笔记 const变量

    在c语言的编程过程中经常会遇到有常数参加运算的运算,比如这种. int a=100*b; 这个100我们叫常数或者叫常量,但是程序中我们不推荐这种直接写常数的方法,有两个缺点. 第一是程序可读性差. ...

  5. Linux uname命令

    一.简介 uname 命令将正在使用的操作系统名写到标准输出中. 二.语法 -a 显示 -m. -n. -r. -s 和 -v 标志指定的所有信息.不能与 -x 或 -SName 标志连用.如果 -x ...

  6. 几种jar转exe方法的比较

    原摘自:https://blog.csdn.net/uikoo9/article/details/7458666 几种jar转exe方法的比较 2012年04月13日 17:33:07 阅读数:153 ...

  7. java全栈day04--方法

    day04内容介绍 1  方法基础知识 2  方法高级内容 3  方法案例 一  方法的概念 A:为什么要有方法 提高代码的复用性 B   什么是方法 完成特定功能的代码块 修饰符  返回值类型  方 ...

  8. [转]MySQL时间与字符串相互转换

    转至:https://www.cnblogs.com/wangyongwen/p/6265126.html 时间.字符串.时间戳之间的互相转换很常用,但是几乎每次使用时候都喜欢去搜索一下用法:本文整理 ...

  9. 基于注解的AOP配置

    配置文件 spring配置文件中的约束 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ...

  10. 【转】Linux将composer的bin目录放到PATH环境变量中

    将composer的bin目录放到PATH环境变量中 使用composer global config bin-dir --absolute查看composer的bin目录 输出类似 Changed ...