zoukankan      html  css  js  c++  java
  • POJ 3977 折半枚举

    链接:

    http://poj.org/problem?id=3977

    题意:

    给你n个数,n最大35,让你从中选几个数,不能选0个,使它们和的绝对值最小,如果有一样的,取个数最小的 

    思路:

    子集个数共有2^n个,所以不能全部枚举,但是可以分为两部分枚举;枚举一半的所有情况,然后后一半二分即可;

    代码:

     1 #include"bits/stdc++.h"
     2 #define N 45
     3 using namespace std;
     4 typedef long long LL;
     5 
     6 int n;
     7 LL a[N];
     8 
     9 LL Abs(LL x)
    10 {
    11     return x<0?-x:x;
    12 }
    13 
    14 int main()
    15 {
    16     while(scanf("%d", &n), n)
    17     {
    18         for(int i=0; i<n; i++)
    19             scanf("%I64d", &a[i]);
    20 
    21         map<LL, int> M;
    22         map<LL, int>::iterator it;
    23         pair<LL, int> ans(Abs(a[0]), 1);
    24 
    25         for(int i=1; i<1<<(n/2); i++)
    26         {
    27             LL sum = 0;int cnt = 0;
    28             for(int j=0; j<(n/2); j++)
    29             {
    30                 if((i>>j)&1)
    31                 {
    32                     sum += a[j];
    33                     cnt ++;
    34                 }
    35             }
    36             ans = min(ans, make_pair(Abs(sum), cnt));///全部是前半部分的;
    37             if(M[sum])///更新cnt为小的;
    38                 M[sum] = min(M[sum], cnt);
    39             else
    40                 M[sum] = cnt;
    41         }
    42 
    43         for(int i=1; i<1<<(n-n/2); i++)
    44         {
    45             LL sum = 0;int cnt = 0;
    46             for(int j=0; j<(n-n/2); j++)
    47             {
    48                 if((i>>j)&1)
    49                 {
    50                     sum += a[j+n/2];
    51                     cnt ++;
    52                 }
    53             }
    54             ans = min(ans, make_pair(Abs(sum), cnt));///全部是后半部分的;
    55 
    56             it = M.lower_bound(-sum);///找到第一个大于-sum的位置,然后取两种情况的最小值;
    57 
    58             if(it != M.end())
    59                 ans = min(ans, make_pair(Abs(sum+it->first), cnt+it->second));
    60             if(it != M.begin())
    61             {
    62                 it--;
    63                 ans = min(ans, make_pair(Abs(sum+it->first), cnt+it->second));
    64             }
    65         }
    66         printf("%I64d %d
    ", ans.first, ans.second);
    67     }
    68     return 0;
    69 }
  • 相关阅读:
    javascript中的继承实现
    【414】Code::Blocks增加主题
    【413】C 语言 Command line
    【412】Linux 系统编译 C 程序
    【411】COMP9024 Assignment1 问题汇总
    【410】Linux 系统 makefile 文件
    Solr的入门知识
    Java8新特性
    Linux命令大全
    为博客园博文添加目录的两种方法
  • 原文地址:https://www.cnblogs.com/mj-liylho/p/9453395.html
Copyright © 2011-2022 走看看