题目大意是给定N个数的集合,从这个集合中找到一个非空子集,使得该子集元素和的绝对值最小。假设有多个答案,输出元素个数最少的那个。

N最多为35,假设直接枚举显然是不行的。

可是假设我们将这些数分成两半后再枚举的话,最多有2^18(262144),此时我们两半枚举后的结果进行排序后再二分搜索一下就能够了。复杂度为O(nlogn)
n最多2^18。

#include <stdio.h>
#include <vector>
#include <math.h>
#include <string.h>
#include <string>
#include <iostream>
#include <queue>
#include <list>
#include <algorithm>
#include <stack>
#include <map> using namespace std; struct MyStruct
{
long long res;
int i;
}; int compp(const void* a1, const void* a2)
{
long long dif = ((MyStruct*)a1)->res - ((MyStruct*)a2)->res;
if (dif > 0)
{
return 1;
}
else if (dif == 0)
{
return 0;
}
else
return -1;
} MyStruct res[2][300000]; inline long long absll(long long X)
{
if (X < 0)
{
return X * (-1);
}
else
return X;
} int main()
{
int n;
#ifdef _DEBUG
freopen("d:\\in.txt", "r", stdin);
#endif
long long values[36];
while (scanf("%d", &n) != EOF)
{
if (n == 0)
{
break;
}
for (int i = 0; i < n; i++)
{
scanf("%I64d", &values[i]);
}
int maxn = n - n / 2;
int maxm = n - maxn;
memset(res, 0, sizeof(res));
for (int i = 0; i < 1 << maxn; i++)
{
res[0][i].i = i;
for (int k = 0; k < 19; k++)
{
if ((i >> k) & 1)
{
res[0][i].res += values[k];
}
}
}
qsort(res[0], 1 << maxn, sizeof(MyStruct), compp);
for (int i = 0; i < 1 << maxm; i++)
{
res[1][i].i = i;
for (int k = 0; k < 19; k++)
{
if ((i >> k) & 1)
{
res[1][i].res += values[k + maxn];
}
}
}
qsort(res[1], 1 << maxm, sizeof(MyStruct), compp);
long long minvalue = 1000000000000000LL;
int mink = 32;
int l = 0;
int r = (1 << maxm);
for (int i = 0; i < 1 << maxn; i++)
{
l = 0;
int curk = 0;
for (int k = 0; k < maxn; k++)
{
if ((res[0][i].i >> k) & 1)
{
curk++;
}
}
while (r - l > 1)
{
int mid = (l + r) / 2;
long long sum = res[1][mid].res + res[0][i].res;
if (sum > 0)
{
r = mid;
}
else
l = mid;
} l = l >= 1 ? l - 1 : l;
for (int k = l; k < (1 << maxm);k++)
{
int curm = 0;
for (int m = 0; m < maxm; m++)
{
if ((res[1][k].i >> m) & 1)
{
curm++;
}
}
if (curm == 0 && curk == 0)
{
continue;
}
long long sum = res[1][k].res + res[0][i].res;
if (absll(sum) < minvalue)
{
mink = curm + curk;
minvalue = absll(sum);
}
else if (absll(sum) == minvalue)
{
mink = min(mink, curk + curm);
}
else if (sum > 0)
{
break;
}
}
}
printf("%I64d %d\n", minvalue, mink);
}
return 0;
}

POJ3977 Subset 折半枚举的更多相关文章

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

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

  2. poj3977(折半枚举+二分查找)

    题目链接:https://vjudge.net/problem/POJ-3977 题意:给一个大小<=35的集合,找一个非空子集合,使得子集合元素和的绝对值最小,如果有多个这样的集合,找元素个数 ...

  3. POJ 3977 - subset - 折半枚举

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

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

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

  5. 折半枚举——poj3977

    暴力搜索超时,但是折半后两部分状态支持合并的情况,可用折半枚举算法 poj3977 给一个序列a[],从里面找到k个数,使其和的绝对值最小 经典折半枚举法+二分解决,对于前一半数开一个map,map[ ...

  6. Load Balancing 折半枚举大法好啊

    Load Balancing 给出每个学生的学分.   将学生按学分分成四组,使得sigma (sumi-n/4)最小.         算法:   折半枚举 #include <iostrea ...

  7. CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。

    1514: Packs Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 4[Submit][Status][Web Board] ...

  8. NYOJ 1091 超大01背包(折半枚举)

    这道题乍一看是普通的01背包,最最基础的,但是仔细一看数据,发现普通的根本没法做,仔细观察数组发现n比较小,利用这个特点将它划分为前半部分和后半部分这样就好了,当时在网上找题解,找不到,后来在挑战程序 ...

  9. Codeforces 888E - Maximum Subsequence(折半枚举(meet-in-the-middle))

    888E - Maximum Subsequence 思路:折半枚举. 代码: #include<bits/stdc++.h> using namespace std; #define l ...

随机推荐

  1. 迅为iMX6开发板支持单核,双核,四核处理器,为客户产品选择提供灵活性

    本文转自迅为:http://topeetboard.com 店铺:https://arm-board.taobao.com 处理器:Freescale Cortex-A9 四核 i.MX6Q 主频 1 ...

  2. mysql-scott用户的表的创建

    /* 功能:创建 scott 数据库中的 dept 表 */ create table dept( deptno int unsigned auto_increment primary key COM ...

  3. TensorFlow低阶API(一)—— 简介

    简介 本文旨在知道您使用低级别TensorFlow API(TensorFlow Core)开始编程.您可以学习执行以下操作: 管理自己的TensorFlow程序(tf.Graph)和TensorFl ...

  4. ssh设置免秘钥登录

    系统:CentOS7.2 需求:A服务器的fab用户需要使用www用户免秘钥登录到B服务器 换句话说,就是在A服务器的fab用户下,ssh    www@B服务ip   -p  端口  ,然后登录过去 ...

  5. com口操作excel

    _Application app;       //Excel应用程序接口 Workbooks books;        //工作薄集合 _Workbook book;     //工作薄 Work ...

  6. vue之package.json文件解析

    1.package.json是什么? 什么是Node.js的模块(Module)?在Node.js中,模块是一个库或框架,也是一个Node.js项目.Node.js项目遵循模块化的架构,当我们创建了一 ...

  7. 问题:hdfs管理界面:Summary部分,Configured Capacity: 0 B

    hdfs管理界面:Summary部分,Configured Capacity: 0 B.正常应该不是0,而是显示系统分配给hdfs的剩余容量. 原因:NameNode的clusterID和DataNo ...

  8. C++ 指针形参和指针引用形参的原理分析

    C++ 函数的参数传递可以分为:值传递和引用传递. 两者的最大区别也很简单,如果该函数的参数只是读的话,值传递就可以满足.如果该函数的参数需要进行修改并返回的时候,就应该进行引用传递. C++指针作为 ...

  9. HYSBZ - 3750 Pieczęć(模拟)

    题目: 一张n*m的方格纸,有些格子需要印成黑色,剩下的格子需要保留白色. 你有一个a*b的印章,有些格子是凸起(会沾上墨水)的.你需要判断能否用这个印章印出纸上的图案.印的过程中需要满足以下要求: ...

  10. mybatis传多个参数(不使用@param注解情况下),3.4.2版本之后出现#{0}-#{n}参数绑定异常

    解决方案: 在mybatis配置文件中声明setting属性的useActualParamName 参数值为false ** 这种方法解决mybatis3.4.2之后的版本产生该问题的解决方法**