POJ3977 Subset 折半枚举
题目大意是给定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 折半枚举的更多相关文章
- POJ 3977 Subset(折半枚举+二分)
SubsetTime Limit: 30000MS Memory Limit: 65536KTotal Submissions: 6754 Accepted: 1277 D ...
- poj3977(折半枚举+二分查找)
题目链接:https://vjudge.net/problem/POJ-3977 题意:给一个大小<=35的集合,找一个非空子集合,使得子集合元素和的绝对值最小,如果有多个这样的集合,找元素个数 ...
- POJ 3977 - subset - 折半枚举
2017-08-01 21:45:19 writer:pprp 题目: • POJ 3977• 给定n个数,求一个子集(非空)• 使得子集内元素和的绝对值最小• n ≤ 35 AC代码如下:(难点:枚 ...
- poj 3977 Subset(折半枚举+二进制枚举+二分)
Subset Time Limit: 30000MS Memory Limit: 65536K Total Submissions: 5721 Accepted: 1083 Descripti ...
- 折半枚举——poj3977
暴力搜索超时,但是折半后两部分状态支持合并的情况,可用折半枚举算法 poj3977 给一个序列a[],从里面找到k个数,使其和的绝对值最小 经典折半枚举法+二分解决,对于前一半数开一个map,map[ ...
- Load Balancing 折半枚举大法好啊
Load Balancing 给出每个学生的学分. 将学生按学分分成四组,使得sigma (sumi-n/4)最小. 算法: 折半枚举 #include <iostrea ...
- CSU OJ PID=1514: Packs 超大背包问题,折半枚举+二分查找。
1514: Packs Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 61 Solved: 4[Submit][Status][Web Board] ...
- NYOJ 1091 超大01背包(折半枚举)
这道题乍一看是普通的01背包,最最基础的,但是仔细一看数据,发现普通的根本没法做,仔细观察数组发现n比较小,利用这个特点将它划分为前半部分和后半部分这样就好了,当时在网上找题解,找不到,后来在挑战程序 ...
- Codeforces 888E - Maximum Subsequence(折半枚举(meet-in-the-middle))
888E - Maximum Subsequence 思路:折半枚举. 代码: #include<bits/stdc++.h> using namespace std; #define l ...
随机推荐
- Farseer.net轻量级ORM开源框架 V1.8版本升级消息
SHA-1: 775a93cf64df3f49c83cc4f4df346afd2075a68f * 发布V1.8.0修复:Oracle的SQL生成 在没有条件时,缺少Where关键字,导致无法分页修复 ...
- 5.4QBXT 模拟赛 (Rank1 机械键盘 蛤蛤)
NOIP2016提高组模拟赛 ——By wangyurzee7 中文题目名称 纸牌 杯具 辣鸡 英文题目与子目录名 cards cups spicychicken 可执行文件名 cards cups ...
- Method Dispatch in Protocol Extensions
We learned in the Protocol-Oriented Programming session at WWDC 2015 that Swift uses two different d ...
- ZXing.dll 生成二维码 C# winform net4.5
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- 背景渐变 background-image:linear-gradient(0deg,#fff,#ccc);
背景渐变 background-image:linear-gradient(0deg,#fff,#ccc);
- CAD参数绘制多段线(com接口)
多段线又被称为多义线,表示一起画的都是连在一起的一个复合对象,可以是直线也可以是圆弧并且它们还可以加不同的宽度. 主要用到函数说明: _DMxDrawX::PathLineTo 把路径下一个点移到指定 ...
- JavaSE-06 二维数组
学习要点 二维数组的定义 二维数组内存数据结构 不规则二维数组 二维数组的定义 语法格式 格式一 数据类型[][] 数组名 = new 数据类型[m][n]; m:表示这个二维数组有多少个一维数组. ...
- 【原】简单shell练习(一)
1.交互式脚本 #!/bin/bash read -p "Enter your name:" name #read提示用户输入 echo "hello $name, we ...
- weblogic启动 web应用ssh关闭 nohup命令
平时我们操作linux服务器的时候,都是通过ssh远程连接,然后启动服务器上的服务的,所以有时候启动weblogic,我们关闭ssh,weblogic 服务也相应的关闭了,那么我们就只能用nohup这 ...
- Javascript创建对象几种方法解析
Javascript创建对象几种方法解析 Javascript面向对象编程一直是面试中的重点,将自己的理解整理如下,主要参考<Javascript高级程序设计 第三版>,欢迎批评指正. 通 ...