码迷,mamicode.com
首页 > 其他好文 > 详细

poj 3977 子集

时间:2018-05-16 19:45:36      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:AC   spl   open   close   href   stdin   技术分享   并且   库函数   

题目

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

分析: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\n",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

 

poj 3977 子集

标签:AC   spl   open   close   href   stdin   技术分享   并且   库函数   

原文地址:https://www.cnblogs.com/shuaihui520/p/9047457.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!