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);
        }
    }
  • 相关阅读:
    JavaScript脚本学习
    PE文件结构 (转贴)
    Squid 代理服务器 编译源码 伪造HTTP_X_FORWARDED_FOR 请求头
    设置win2003远程桌面允许2个以上会话
    2003远程桌面声音问题
    AS3正则表达式
    Visual Studio技巧之打造拥有自己标识的代码模板
    如何重建sql数据库索引
    多线程系列(转)
    时间差
  • 原文地址:https://www.cnblogs.com/stxy-ferryman/p/9626529.html
Copyright © 2011-2022 走看看