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.将集合中的元素分成两 ...
随机推荐
- 【264】◀▶ Windows 批处理(CMD)
参考:Windows Commands 微软官方帮助 参考:DOS命令自学小窍门:巧用help命令 参考:bat批处理的注释语句 打开文件夹: start D:\abc 打开D盘abc文件夹 打开ex ...
- scp命令 跨服务器传输
scp命令用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度.当你服务器硬盘变为只读read onl ...
- ListView里面adapter的不同分类的item
public class PlayAdapter extends BaseAdapter { /** * 标题的item */ public static final int ITEM_TITLE = ...
- matlab 修改文件夹下所有文件名大写为小写
1. path = './DIR/';Files = dir(fullfile(path,'*.m'));LengthFiles = length(Files);for count_i = 1 : L ...
- java中byte是什么类型,和int有什么区别
byte字节型,int是整型,byte是8bit,int是32bit. byte可以转换为int,但int转byte可能会报错,因为精度问题,可能会超过上界.char也可转int,互转int的关系和b ...
- 导入project后lib文件夹一直没有jar包
原因: 导入project,倒错了项目,只因为后面新建的项目名称有和前面的差不多,导致自己选择了原来的项目,因此,项目的注解一直报错.
- 形式化验证工具(PAT)羊车门代码学习
首先介绍一下PAT工具,下图是PAT工具的图标 PAT工具全称是Process Analysis Toolkit,可以做一些简单的验证. 今天我们分析一下例子里面的Monty Hall Problem ...
- img中 src 中文路径解决办法
最近有个项目场景如下:需要后台遍历图片.视频所在的文件夹,获取的到的路径传递到JSP页面,使用<img src="具体的路径">显示图片.遇到的问题:如果图片的路径.图 ...
- kaggle House_Price_XGBoost
kaggle House_Price_final 代码 import numpy as np import pandas as pd from sklearn.ensemble import Rand ...
- 在OnRowDataBound或OnItemDataBound事件中获取字段值
不管是在GridView,DataList还是Repeater控件中,其中Repeater控件,没有DataKeyNames或是DataKeyField属性,想获取记录的主键值,只好用Label或是H ...