zoukankan      html  css  js  c++  java
  • POJ 3977 Subset(折半枚举+二分)

    Subset
    Time Limit: 30000MS        Memory Limit: 65536K
    Total Submissions: 6754        Accepted: 1277

    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
    Seventh ACM Egyptian National Programming Contest

    题解:给出n个数,让你取出一个子集,使子集和的绝对值最小,如果有多个构成相同绝对值的方案,取子集个数最小的

    求最小绝对值和最小大小

    题解:数据范围可以猜出是折半枚举,前一半的数可以在len×2^(n/2)内求出,然后再暴力枚举后一半的和sum,在前一半的所有答案中找出与-sum最相近的两个数,对于sum所产生的贡献,答案肯定只会由这两个数+sum影响。当然还要考虑空集的情况,也就是只取前面或者只取后面

    代码如下:

    #include<map>
    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define lson ch[x][0]
    #define rson ch[x][1]
    #define hi puts("hi!");
    #define int long long
    #define mp make_pair
    #define pii pair<int,int>
    using namespace std;
    
    int n,len1,len2,a[40];
    map<int,int> m;
    
    long long absl(long long x)
    {
        return x>0ll?x:-x;
    }
    
    signed main()
    {
        while(~    scanf("%lld",&n)&&n)
        {
            m.clear();
            pii ans=mp(1e18,0ll);
            for(int i=0;i<n;i++) scanf("%lld",&a[i]);
            len1=n/2;
            len2=n-len1;
            for(int i=1;i<1<<len1;i++)
            {
                int cnt=0,sum=0;
                for(int j=0;j<len1;j++)
                {
                    if(i&(1<<j))
                    {
                        cnt++;
                        sum+=a[j];
                    }
                }
                if(!m.count(sum)||m[sum]>cnt) m[sum]=cnt;
                if(ans>mp(absl(sum),cnt)) ans=mp(absl(sum),cnt);
            }
            for(int i=1;i<1<<len2;i++)
            {
                int cnt=0,sum=0;
                for(int j=0;j<len2;j++)
                {
                    if(i&(1<<j))
                    {
                        cnt++;
                        sum+=a[len1+j];
                    }
                }
                if(ans>mp(absl(sum),cnt)) ans=mp(absl(sum),cnt);
                map<long long,long long>::iterator it=m.lower_bound(-sum);
                if(it!=m.end())
                {
                    if(ans>mp(absl(sum+it->first),cnt+it->second))
                    {
                        ans=mp(absl(sum+it->first),cnt+it->second);
                    }
                }
                if(it!=m.begin()) it--;
                if(it!=m.end())
                {
                    if(ans>mp(absl(sum+it->first),cnt+it->second))
                    {
                        ans=mp(absl(sum+it->first),cnt+it->second);
                    }
                }
            }
            printf("%lld %lld
    ",ans.first,ans.second);
        }
    }
  • 相关阅读:
    视图同义词创建
    单据打印模板默认启用打印机本身设置尺寸设置方法
    C语言结构体指针成员强制类型转换
    swoole中swoole_timer_tick回调函数使用对象方法
    利用phpspreadsheet切割excel大文件
    实例讲解如何利用jQuery设置图片居中放大或者缩小
    PHP小练习题
    html5中的progress兼容ie,制作进度条样式
    html5 图片热点area,map的用法
    详解JavaScript中的arc的方法
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9626529.html
Copyright © 2011-2022 走看看