Subset
Time Limit: 30000MS | Memory Limit: 65536K | |
Total Submissions: 6499 | Accepted: 1227 |
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
题目的意思 你可以取非空集合 任意组合 看看能不能绝对值最小 也就是越接近0
我们怎么看这题 我们先想 这有35个东西
又是组合 很容易想到二进制枚举 但是2^35太大了
那么我们又为了能做题 想到2^17是个比较好的范围
那么我们就可以对半枚举了
把前n/2个和后n/2个分开 进行枚举
从i=0到(1<<n/2)-1(可以取) 为什么从0开始呢?
因为我们可以是一个空集 加 一个非空集 组合 也是一个非空集合
那我们马上发现 两个空集合加起来肯定是空集合
所以如果枚举的两个集合都是空集 那么得到的也是空集
所以我们可以进行二进制枚举了
前面写了一发 不知道为啥WA 目前还不知道
重新写了就过了。。。
lower_bound不能直接对结构体 所以开一个新数组
并且在找到的xb左右范围进行二分 防止迷之二分
注意判断下边界条件
/*
POJ 3977
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
#define dbg(x) ;
ll arr[45];
ll ans_new[1<<18];
ll ABS(ll a){
if(a>=0) return a;
return -a;
}
struct node {
ll sum;
int num;
bool operator < (const node other) const
{
if(sum==other.sum) return num < other.num;
return sum<other.sum;
}
}ans_l[1<<18],ans_r[1<<18];
int main(){
int n;
while(scanf("%d",&n)&&n){
for(int i= 1;i<=n;++i) scanf("%lld",&arr[i]);
int tmp_l = n/2;
int tmp_r = n-tmp_l;
for(int i = 0;i<(1<<tmp_l);i++){
ans_l[i].sum = 0;
int cnt = 1,cnt_now = 0,now_i = i;
while(now_i){
if(now_i&1){
cnt_now ++;
ans_l[i].sum += arr[cnt];
}
cnt++;
now_i/=2;
}
ans_l[i].num = cnt_now;
}
for(int i = 0;i<(1<<tmp_r);i++){
ans_r[i].sum = 0;
int cnt = 1,cnt_now = 0,now_i = i;
while(now_i){
if(now_i&1){
cnt_now ++;
ans_r[i].sum += arr[cnt+tmp_l];
}
cnt++;
now_i/=2;
}
ans_r[i].num = cnt_now;
ans_new[i] = ans_r[i].sum;
}
ll maxx = INF;
int num = 0;
sort(ans_r,ans_r+(1<<tmp_r));
sort(ans_new,ans_new+(1<<tmp_r));
for(int i = 0 ;i<(1<<tmp_l);i++){
int xb = lower_bound(ans_new,ans_new+(1<<tmp_r),-ans_l[i].sum)-ans_new;
for(int j = xb-1;j<=xb+1;j++){
if(j<0||j>=(1<<tmp_r)) continue;
if(ans_r[j].num==0&&ans_l[i].num==0) continue;
if(maxx>ABS(ans_new[j]+ans_l[i].sum)){
maxx = ABS(ans_new[j]+ans_l[i].sum);
num = ans_r[j].num+ans_l[i].num;
dbg(ans_r[j].num);
dbg(ans_l[i].num);
dbg(ans_new[j]);
dbg(ans_l[i].sum);
dbg(num);
dbg(maxx);
}
else if(maxx == ABS(ans_new[j]+ans_l[i].sum)){
if(num> ans_r[j].num+ans_l[i].num) num = ans_r[j].num+ ans_l[i].num;
}
}
}
printf("%lld %d\n",maxx,num);
}
return 0;
}