zoukankan      html  css  js  c++  java
  • 2A Subset——折半枚举+二分

    题目

    Given a list of N integers with absolute values no larger than (10^15), 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 (10^15) 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<=35,TLE无疑了
    而如果看一半,18还是可以的
    所以这道题就是将这些数分成前后两半,分别计算
    算后面的时候在前面二分查找相反数最接近的数进行计算
    这道题用int会会爆掉,要用到long long
    但这样abs就不能用了,得自己手写一个

    代码

    #include <cstdio>
    #include <cmath>
    #include <map>
    #define int long long
    using namespace std;
    const int N = 1e3+5;
    int n, a[N];
    int mabs(int x) {
        return x > 0 ? x : -x;
    }
    signed main() {
        while (1) {
            scanf("%lld", &n);
            if (!n) break;
            for(int i = 1; i <= n; i++)
                scanf("%lld", &a[i]);
            int half = n >> 1;
            pair<int, int> ans(mabs(a[1]), 1);
            map<int, int> m;
            map<int, int>::iterator it;
            for(int s = 1; s < (1 << half); s++) {
                int sum = 0, cnt = 0;
                for(int i = 1; i <= half; i++)
                    if (s & (1 << (i - 1))) sum += a[i], cnt++;
                pair<int, int> x(mabs(sum), cnt);
                ans = min(ans, x);
                if (m[sum]) m[sum] = min(m[sum], cnt);
                else m[sum] = cnt;
            }
            for(int s = 1; s < (1 << (n - half)); s++) {
                int sum = 0, cnt = 0;
                for(int i = 1; i <= n - half; i++)
                    if (s & (1 << (i - 1))) sum += a[i+half], cnt++;
                pair<int, int> x(mabs(sum), cnt);
                ans = min(ans, x);
                it = m.lower_bound(-sum);
                if (it != m.end()) {
                    pair<int, int> x(mabs(sum + it->first), cnt + it->second);
                    ans = min(ans, x);
                    
                }
                if (it != m.begin()) {
                    it--;
                    pair<int, int> x(mabs(sum + it->first), cnt + it->second);
                    ans = min(ans, x);
                }
            }
            printf("%lld %lld
    ", ans.first, ans.second);
        }
        return 0;
    }
    
  • 相关阅读:
    git变慢的原因
    MongoDB存储过程创建和使用一例
    关于小游戏的槛和限制
    【转载】如何查看本机电脑的公网IP
    【转载】C#如何获取DataTable中某列的数据类型
    【转载】C#的DataTable使用NewRow方法创建新表格行
    【转载】如何删除Windows远程桌面保存的账号密码数据
    【转载】 C#中ArrayList使用GetRange方法获取某一段集合数据
    【转载】 C#中常见的泛型集合类有哪些
    【转载】C#中使用Insert方法往ArrayList集合指定索引位置插入新数据
  • 原文地址:https://www.cnblogs.com/shawk/p/12774440.html
Copyright © 2011-2022 走看看