• poj 3977 Subset(折半枚举+二进制枚举+二分)


    Subset
    Time Limit: 30000MS   Memory Limit: 65536K
    Total Submissions: 5721   Accepted: 1083

    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

     

    题意:给你一个含n(n<=35)个数的数组,让你在数组中选出一个非空子集,使其元素和的绝对值最小,输出子集元素的个数以及元素和的绝对值,若两个子集元素和相等,输出元素个数小的那个。

    思路:如果直接暴力枚举,复杂度O(2^n),n为35时会超时,故可以考虑折半枚举,利用二进制将和以及元素个数存在两个结构体数组中,先预判两个结构体是否满足题意,再将其中一个元素和取相反数后排序,因为总元素和越接近零越好,再二分查找即可,用lower_bound时考虑查找到的下标和他前一个下标,比较元素和以及元素个数,不断更新即可。

    详见代码注释

    poj的long long abs要自己写

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cmath>
      5 using namespace std;
      6 struct Z 
      7 {
      8     long long int x;
      9     int y;
     10     bool operator < (const Z& b)const
     11     {
     12         if (x != b.x)
     13             return x < b.x;
     14         return y<b.y;
     15 
     16     }
     17 }a[300005], b[300005];
     18 
     19 long long  int c[40];
     20 
     21 long long int abs1(long long int x) 
     22 {
     23     if (x<0)
     24         return -x;
     25     return x;
     26 }
     27 
     28 int main()
     29 {
     30     int n;
     31     int i,j;
     32     while (cin >> n && n)
     33     {
     34         for (i = 0; i < 300005; i++)
     35         {
     36             a[i].x = a[i].y = b[i].x = b[i].y = 0;
     37         }
     38         long long sum = 1e17;
     39         int ans = 40;
     40         for (i = 0; i < n; i++)
     41         {
     42             cin >> c[i];
     43         }
     44         int n1 = n / 2;
     45         for (i = 0; i < (1 << n1); i++)//二进制枚举一半,共2的n1次方种
     46         {
     47             for (j = 0; j < n1; j++)
     48             {
     49                 if (i >> j&1 && (i != 0 || j != 0))//这一半中的所有情况列出来
     50                 {
     51                     a[i - 1].x+= c[j];
     52                     a[i - 1].y++;//记录这个数含有几个元素
     53                 }
     54             }
     55         }
     56         int n2 = n - n1;
     57         for (i = 0; i < (1 << n2); i++)//同理初始化
     58         {
     59             for (j = 0; j < n2; j++)
     60             {
     61                 if (i >> j & 1 && (i != 0 || j != 0))
     62                 {
     63                     b[i - 1].x += c[j + n1];
     64                     b[i - 1].y++;
     65                 }
     66             }
     67         }
     68         //对这两半单独检查更新最小和sum和最小元素数ans
     69         for (i = 0; i < (1 << n1) - 1; i++)//
     70         {
     71             if (abs1(a[i].x) < sum)
     72             {
     73                 sum = abs1(a[i].x);
     74                 ans = a[i].y;
     75             }
     76             else if (abs1(a[i].x) == sum && a[i].y < ans)
     77             {
     78                 ans=a[i].y;
     79                 sum = abs1(a[i].x);
     80             }
     81         }
     82 
     83         for (i = 0; i<(1 << n1) - 1; i++)//前半部分变为相反数
     84             a[i].x = -a[i].x;
     85         for (i = 0; i<(1 << n2) - 1; i++) //另一半检查
     86         {
     87             if (abs1(b[i].x)<sum) 
     88             {
     89                 sum = abs1(b[i].x);
     90                 ans = b[i].y;
     91             }
     92             else if (abs1(b[i].x) == sum && b[i].y<ans) 
     93             {
     94                 ans = b[i].y;
     95                 sum = abs1(b[i].x);
     96             }
     97         }
     98 
     99         sort(a, a + (1 << n1) - 1);
    100         sort(b, b + (1 << n2) - 1);
    101 
    102         for (i = 0; i < (1 << n1)-1; i++)//两半合起来检查
    103         {
    104             int t = lower_bound(b, b + (1 << n2) - 1, a[i])- b;//t是序号
    105             if (t > 0)//查看该序号周围的数
    106             {
    107                 if (abs1(b[t - 1].x - a[i].x) < sum)//和可以更小
    108                 {
    109                     sum = abs1(b[t - 1].x - a[i].x);//更新最小绝对值和
    110                     ans = b[t - 1].y + a[i].y;//更新元素个数
    111                 }
    112                 else if (abs1(b[t - 1].x - a[i].x) == sum && b[t - 1].y + a[i].y < ans)//元素个数可以更小
    113                 {
    114                     sum = abs1(b[t - 1].x - a[i].x);
    115                     ans = b[t - 1].y + a[i].y;
    116                 }
    117             }
    118             if (t < (1 << n2) - 1)
    119             {
    120                 if (abs1(b[t].x - a[i].x) < sum)
    121                 {
    122                     sum = abs1(b[t].x - a[i].x);
    123                     ans = b[t].y + a[i].y;
    124                 }
    125                 else if (abs1(b[t].x - a[i].x) == sum && b[t].y + a[i].y<ans) 
    126                 {
    127                     sum = abs1(b[t].x - a[i].x);
    128                     ans = b[t].y + a[i].y;
    129                 }
    130             }
    131         }
    132         cout << sum << " " << ans << endl;
    133     }
    134     return 0;
    135 }
  • 相关阅读:
    黄聪:C#多线程教程(1):BeginInvoke和EndInvoke方法,解决主线程延时Thread.sleep柱塞问题(转)
    黄聪:C#类似Jquery的html解析类HtmlAgilityPack基础类介绍及运用
    黄聪:国内com域名转移到Godaddy详细教程(转)
    黄聪:Navicat for MySQL的1577错误解决
    黄聪:VPS配置Filezilla Server支持FTP的Passive被动模式(FTP连接不上怎么办?有详细教程)
    黄聪:Microsoft office 2013版下载、安装及破解工具下载破解教程(Windows Toolkit)
    黄聪:mysql搬家,直接复制data文件夹(*.MYD,*.MYI,innodb)出错,无法正常显示
    黄聪:WordPress默认编辑器可视化切换不见了,非插件导致消失问题
    黄聪:自定义WordPress顶部管理工具条的技巧(转)
    黄聪:VS2010中“新建项目”却没有“解决方案”节点,如何调出来
  • 原文地址:https://www.cnblogs.com/caiyishuai/p/13271174.html
Copyright © 2020-2023  润新知