zoukankan      html  css  js  c++  java
  • poj 3977 子集

    题目

    题意:在一个集合中找到一个非空子集使得这个子集元素和的绝对值尽量小,和绝对值相同时保证元素个数尽量小

    分析:1.二分枚举的思想,先分成两个集合;

           2.枚举其中一个集合中所有的子集并且存到数组中,并排序;

          3.枚举另一个集合中所有的子集并且与第一个集合中的合适子集相加(可以通过二分查找在数组中找到最合

    适的元素)

      4.这个题特别坑的地方是不能用abs库函数,只能手写

    AC代码:

    #include<stdio.h>
    #include<map>
    #include<algorithm>
    using namespace std;
    #define ll long long
    ll a[50];
    ll Abs(ll x)
    {
        return x<0?-x:x;
    }
    int main( )
    {
      int n;
      while(scanf("%d",&n)!=EOF)
      {    
          if(n==0)
            break;
          for(int i=0 ; i<n ; i++)
           scanf("%lld",&a[i]);
          int n2=n/2;
          pair<ll,int> ans(Abs(a[0]),1);
          map<ll,int>M;
          map<ll,int>::iterator it;
          for(int i=1 ; i<1<<n2 ; i++)
          {
              ll sum=0;int cnt=0;
              for(int j=0 ; j<n2 ; j++)
              {
                  if(i>>j&1)
                  {
                      sum+=a[j];
                      cnt++;
                  }
              }
              ans = min(ans,make_pair(Abs(sum),cnt));
              if(M[sum])
                M[sum]=min(M[sum],cnt);
              else
                M[sum]=cnt;
          }
          for(int i=1 ; i<1<<(n-n2) ; i++)
          {
              ll sum=0;int cnt=0;
              for(int j=0 ; j<n-n2 ; j++)
              {
                  if(i>>j&1)
                  {
                      sum+=a[j+n2];
                      cnt++;
                  }
    
              }
              ans=min(ans,make_pair(Abs(sum),cnt));
              it = M.lower_bound(-sum);
              if(it != M.end())
                ans = min(ans,make_pair(Abs(sum+it->first),cnt+it->second));
              if(it != M.begin())
                {
                    it--;
                   ans = min(ans,make_pair(Abs(sum+it->first),cnt+it->second));
                }
                
          }
          printf("%lld %d
    ",ans.first,ans.second);
      }
      return 0;
    
    }
    View Code

    带解析

    #include <iostream>
    #include <algorithm>
    #include <limits>
    #include <map>
    using namespace std;
    typedef long long LL;
    #define MAX_N 36
    LL number[MAX_N];
     
    LL ll_abs(const LL& x)    // damn it! error C3861: 'llabs': identifier not found
    {
        return x >= 0 ? x : -x;
    }
     
    ///////////////////////////SubMain//////////////////////////////////
    int main(int argc, char *argv[])
    {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
        freopen("out.txt", "w", stdout);
    #endif
        int N;
        while (cin >> N && N)
        {
            for (int i = 0; i < N; ++i)
            {
                cin >> number[i];
            }
            map<LL, int> dp;    // sum的值<->集合元素个数,这里不是绝对值
            pair<LL, int> result(ll_abs(number[0]), 1);    // 最优解
            for (int i = 0; i < 1 << (N / 2); ++i)    // 枚举前 N / 2
            {
                LL sum = 0;
                int num = 0;
                for (int j = 0; j < N / 2; ++j)
                {
                    if ((i >> j) & 1)
                    {
                        sum += number[j];
                        ++num;
                    }
                }
                if (num == 0)
                {
                    continue;
                }
                result = min(result, make_pair(ll_abs(sum), num));
                map<LL, int>::iterator it = dp.find(sum);
                if (it != dp.end())
                {
                    it->second = min(it->second, num);
                }
                else
                {
                    dp[sum] = num;
                }
            }
     
            for (int i = 0; i < 1 << (N - N / 2); ++i)    // 枚举剩下的
            {
                LL sum = 0;
                int num = 0;
                for (int j = 0; j < N - N / 2; ++j)
                {
                    if ((i >> j) & 1)
                    {
                        sum += number[N / 2 + j];
                        ++num;
                    }
                }
                if (num == 0)
                {
                    continue;
                }
                result = min(result, make_pair(ll_abs(sum), num));
                // 找寻跟-sum最相近的结果
                map<LL, int>::iterator it = dp.lower_bound(-sum);    // 返回大于或等于-sum的第一个元素位置
                if (it != dp.end())
                {// 可能是该位置
                    result = min(result, make_pair(ll_abs(sum + it->first), num + it->second));
                }
                if (it != dp.begin())
                {// 或比该元素小一点点的
                    --it;
                    result = min(result, make_pair(ll_abs(sum + it->first), num + it->second));
                }
            }
            cout << ll_abs(result.first) << ' ' << result.second << endl;
        }
    #ifndef ONLINE_JUDGE
        fclose(stdin);
        fclose(stdout);
        system("out.txt");
    #endif
        return 0;
    }
    View Code
  • 相关阅读:
    Js:返回上一页
    select设置选中项/select的级联
    js闭包
    bootstrap
    My97DatePicker使用 、layDate 日期与时间组件
    IO流
    java之String工具类和File类
    Python学习之路文件file常用方法
    Python学习之路-集合set的常用方法
    Python学习之路-字典外传
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/9047457.html
Copyright © 2011-2022 走看看