题目大意是给定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. Protostuff序列化和反序列化

    序列化和反序列化是在应对网络编程最常遇到的问题之一. 序列化就是将Java Object转成byte[]:反序列化就是将byte[]转成Java Object. 这里不介绍JDK serializab ...

  2. Vue.js语法糖整理

    el:element 需要获取的元素,一定是HTML中的根容器元素 data:用于数据的存储 methods:用于存储各种方法 数据绑定字面量只加载一次{{* msg}} data里面可以进行简单的运 ...

  3. 使用Gson解析Json数组遇到的泛型类型擦除问题解决方法

    谷歌Gson转换Json串有如下方法: public Object fromJson(String json, Type typeOfT);1可以使用它进行数组解析.如下,使用此方法解析Json串为类 ...

  4. sosoapi的安装

    sosoapi简介及其用户手册:http://www.sosoapi.com/pass/help/manual.htm 该随笔的大概分为: 1.sosoapi的基础安装  2.sosoapi使用域名访 ...

  5. CE工具里自带的学习工具--第三关

    图解: 重复第5,6,7,8,9步,最终得到:

  6. 第3节 hive高级用法:14、hive的数据压缩

    六.hive的数据压缩 在实际工作当中,hive当中处理的数据,一般都需要经过压缩,前期我们在学习hadoop的时候,已经配置过hadoop的压缩,我们这里的hive也是一样的可以使用压缩来节省我们的 ...

  7. iOS缓存到sandbox

        在手机应用程序开发中,为了减少与服务端的交互次数,加快用户的响应速度,一般都会在iOS设备中加一个缓存的机制,前面一篇文章介绍了iOS设备的内存缓存,这篇文章将设计一个本地缓存的机制. 功能需 ...

  8. 基于Redis的三种分布式爬虫策略

    前言: 爬虫是偏IO型的任务,分布式爬虫的实现难度比分布式计算和分布式存储简单得多. 个人以为分布式爬虫需要考虑的点主要有以下几个: 爬虫任务的统一调度 爬虫任务的统一去重 存储问题 速度问题 足够“ ...

  9. jQuery的ready与js的load事件的区别

    摘自:http://www.cnblogs.com/see7di/archive/2011/07/15/2239677.html 为了理解这两个事件的异同,读者应该先了解HTML文档加载的顺序. DO ...

  10. python爬虫入门02:教你通过 Fiddler 进行手机抓包

    哟~哟~哟~ hi起来 everybody 今天要说说怎么在我们的手机抓包 通过 python爬虫入门01:教你在Chrome浏览器轻松抓包 我们知道了 HTTP 的请求方式 以及在 Chrome 中 ...