ACM - ICPC

Subset POJ - 3977(折半枚举+二分查找)

2018-07-25  本文已影响57人  JesHrz

题目来源:Subset

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

题意

给定n个数,求这n个数所构成的集合的某个子集,使得这个子集中所有数和的绝对值最小,输出和的绝对值以及集合中数的个数。

思路

n是小于35的,直接枚举集合复杂度为2n,超时。可以枚举前n/2个数的集合,然后枚举后n/2个数的集合再在前面的集合中二分查找,这样复杂度为2(n/2) log(n/2)。

代码

#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
inline long long Abs(long long x)
{
    return x > 0 ? x : -x;
}
int n;
long long a[40];
int main()
{
    while (cin >> n)
    {
        if (n == 0)
            break;
        for (int i = 1; i <= n; ++i)
            cin >> a[i];
        map<long long, int>mmp;
        long long ans = Abs(a[1]);
        int len = n;
        for (int i = 1; i < (1 << (n / 2)); ++i)
        {
            long long sum = 0;
            int j = i, cnt = 0, pos = 1;
            while (j && pos <= n / 2)
            {
                if (j & 1)
                {
                    sum += a[pos];
                    cnt++;
                }
                j >>= 1;
                pos++;
            }
            if (Abs(sum) < ans)
            {
                ans = Abs(sum);
                len = cnt;
            }
            else if (Abs(sum) == ans)
            {
                len = min(len, cnt);
            }

            if (mmp[sum])
                mmp[sum] = min(mmp[sum], cnt);
            else
                mmp[sum] = cnt;
        }
        for (int i = 1; i < (1 << (n - n / 2)); ++i)
        {
            long long sum = 0;
            int cnt = 0, pos = 1, j = i;
            while (j && pos + n / 2 <= n)
            {
                if (j & 1)
                {
                    sum += a[pos + n / 2];
                    cnt++;
                }
                j >>= 1;
                pos++;
            }
            
            if (Abs(sum) < ans)
            {
                ans = Abs(sum);
                len = cnt;
            }
            else if (Abs(sum) == ans)
            {
                len = min(len, cnt);
            }
            map<long long, int>::iterator it = mmp.lower_bound(-sum);
            if (it != mmp.end())
            {
                if (Abs(sum + it->first) < ans)
                {
                    ans = Abs(sum + it->first);
                    len = cnt + it->second;
                }
                else if (Abs(sum + it->first) == ans)
                {
                    len = min(len, cnt + it->second);
                }
            }
            if (it != mmp.begin())
            {
                it--;
                if (Abs(sum + it->first) < ans)
                {
                    ans = Abs(sum + it->first);
                    len = cnt + it->second;
                }
                else if (Abs(sum + it->first) == ans)
                {
                    len = min(len, cnt + it->second);
                }
            }
        }
        cout << Abs(ans) << ' ' << len << endl;
    }
    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读