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

Description

Given a list of N integers with absolute values no larger than 1015, find a non empty subset of these numbers which minimizes the absolute value of the sum of its elements. In case there are multiple subsets, choose the one with fewer elements.

Input

The input contains multiple data sets, the first line of each data set contains N <= 35, the number of elements, the next line contains N numbers no larger than 1015 in absolute value and separated by a single space. The input is terminated with N = 0

Output

For each data set in the input print two integers, the minimum absolute sum and the number of elements in the optimal subset.

Sample Input

1
10
3
20 100 -100
0

Sample Output

10 1
0 2

Source

 

题意:给你一个含n(n<=35)个数的数组,让你在数组中选出一个非空子集,使其元素和的绝对值最小,输出子集元素的个数以及元素和的绝对值,若两个子集元素和相等,输出元素个数小的那个。

思路:如果直接暴力枚举,复杂度O(2^n),n为35时会超时,故可以考虑折半枚举,利用二进制将和以及元素个数存在两个结构体数组中,先预判两个结构体是否满足题意,再将其中一个元素和取相反数后排序,因为总元素和越接近零越好,再二分查找即可,用lower_bound时考虑查找到的下标和他前一个下标,比较元素和以及元素个数,不断更新即可。

详见代码注释

poj的long long abs要自己写

 #include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
struct Z
{
long long int x;
int y;
bool operator < (const Z& b)const
{
if (x != b.x)
return x < b.x;
return y<b.y; }
}a[], b[]; long long int c[]; long long int abs1(long long int x)
{
if (x<)
return -x;
return x;
} int main()
{
int n;
int i,j;
while (cin >> n && n)
{
for (i = ; i < ; i++)
{
a[i].x = a[i].y = b[i].x = b[i].y = ;
}
long long sum = 1e17;
int ans = ;
for (i = ; i < n; i++)
{
cin >> c[i];
}
int n1 = n / ;
for (i = ; i < ( << n1); i++)//二进制枚举一半,共2的n1次方种
{
for (j = ; j < n1; j++)
{
if (i >> j& && (i != || j != ))//这一半中的所有情况列出来
{
a[i - ].x+= c[j];
a[i - ].y++;//记录这个数含有几个元素
}
}
}
int n2 = n - n1;
for (i = ; i < ( << n2); i++)//同理初始化
{
for (j = ; j < n2; j++)
{
if (i >> j & && (i != || j != ))
{
b[i - ].x += c[j + n1];
b[i - ].y++;
}
}
}
//对这两半单独检查更新最小和sum和最小元素数ans
for (i = ; i < ( << n1) - ; i++)//?
{
if (abs1(a[i].x) < sum)
{
sum = abs1(a[i].x);
ans = a[i].y;
}
else if (abs1(a[i].x) == sum && a[i].y < ans)
{
ans=a[i].y;
sum = abs1(a[i].x);
}
} for (i = ; i<( << n1) - ; i++)//前半部分变为相反数
a[i].x = -a[i].x;
for (i = ; i<( << n2) - ; i++) //另一半检查
{
if (abs1(b[i].x)<sum)
{
sum = abs1(b[i].x);
ans = b[i].y;
}
else if (abs1(b[i].x) == sum && b[i].y<ans)
{
ans = b[i].y;
sum = abs1(b[i].x);
}
} sort(a, a + ( << n1) - );
sort(b, b + ( << n2) - ); for (i = ; i < ( << n1)-; i++)//两半合起来检查
{
int t = lower_bound(b, b + ( << n2) - , a[i])- b;//t是序号
if (t > )//查看该序号周围的数
{
if (abs1(b[t - ].x - a[i].x) < sum)//和可以更小
{
sum = abs1(b[t - ].x - a[i].x);//更新最小绝对值和
ans = b[t - ].y + a[i].y;//更新元素个数
}
else if (abs1(b[t - ].x - a[i].x) == sum && b[t - ].y + a[i].y < ans)//元素个数可以更小
{
sum = abs1(b[t - ].x - a[i].x);
ans = b[t - ].y + a[i].y;
}
}
if (t < ( << n2) - )
{
if (abs1(b[t].x - a[i].x) < sum)
{
sum = abs1(b[t].x - a[i].x);
ans = b[t].y + a[i].y;
}
else if (abs1(b[t].x - a[i].x) == sum && b[t].y + a[i].y<ans)
{
sum = abs1(b[t].x - a[i].x);
ans = b[t].y + a[i].y;
}
}
}
cout << sum << " " << ans << endl;
}
return ;
}

poj 3977 Subset(折半枚举+二进制枚举+二分)的更多相关文章

  1. POJ 3977 - subset - 折半枚举

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

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

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

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

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

  4. POJ 3977 Subset | 折半搜索

    题目: 给出一个整数集合,求出非空子集中元素和绝对值最小是多少(元素个数尽量少) 题解: 分成两半 爆搜每一半,用map维护前一半的值 每搜出后一半的一个值就去map里找和他和绝对值最小的更新答案 # ...

  5. POJ.3279 Fliptile (搜索+二进制枚举+开关问题)

    POJ.3279 Fliptile (搜索+二进制枚举+开关问题) 题意分析 题意大概就是给出一个map,由01组成,每次可以选取按其中某一个位置,按此位置之后,此位置及其直接相连(上下左右)的位置( ...

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

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

  7. POJ 3279 Fliptile(反转 +二进制枚举)

    Fliptile Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 13631   Accepted: 5027 Descrip ...

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

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

  9. POJ 1753 Flip Game(二进制枚举)

    题目地址链接:http://poj.org/problem?id=1753 题目大意: 有4*4的正方形,每个格子要么是黑色,要么是白色,当把一个格子的颜色改变(黑->白或者白->黑)时, ...

随机推荐

  1. office在繁体系统下 导入导出 功能灰显的解决方法

    当在win7系统使用繁体中文版的office时,或系统是繁体版时,可能会导致office的导入导出功能无法使用 解决方法: 控制面板--区域和语言--格式--中文简体

  2. Http权威指南(cookie以及web认证机制)

    其实对于cookie,想必大家都不陌生,cookie目前主要用于客户端的识别技术. 说到客户端识别技术,就不得不说一个登录态的问题了.登录态顾名思义,用于验证用户的登录与否. 1.登录态 对于PC端网 ...

  3. Photon——Feature Overview 功能概述

    Photon——Feature Overview 功能概述   Feature Overview 功能概述        Photon is a real-time socket server and ...

  4. HDU 3345

    http://acm.hdu.edu.cn/showproblem.php?pid=3345 最近重写usaco压力好大,每天写的都想吐.. 水一道bfs 注意的是开始旁边有敌人可以随便走,但是一旦开 ...

  5. sql server不能删除数据库,显示错误:正在使用

    解决办法: use mastergoalter database database_name set single_user with rollback immediate --将数据库回滚到原始配置 ...

  6. C++语言的url encode 和decode

    std::string UrlEncode(const std::string& szToEncode) { std::string src = szToEncode; char hex[] ...

  7. Python 实现windows后台服务

    # -*- coding: utf-8 -*- import sys import win32api import win32con import win32event import win32ser ...

  8. navicat如何设置外键

    今天上午刚刚弄明白了在navicat for mysql上如何设置外键,现在分享出来,希望能够对大家有帮助. 先介绍一下基本情况.现在有两个表一张是teacher表一张是dept表,现在我想把teac ...

  9. BZOJ3926 Zjoi2015 诸神眷顾的幻想乡【广义后缀自动机】

    Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...

  10. python笔记-10(socket提升、paramiko、线程、进程、协程、同步IO、异步IO)

    一.socket提升 1.熟悉socket.socket()中的省略部分 socket.socket(AF.INET,socket.SOCK_STREAM) 2.send与recv发送大文件时对于黏包 ...