POJ 3977 Subset (折半枚举)

来源:互联网 发布:淘宝店铺层级怎么算 编辑:程序博客网 时间:2024/05/15 09:39

题意:让你从n个数里面找任意个数(>0),使他们的和的绝对值最小,输出最小和的绝对值和最小个数。


分析:

      分成两份,分别枚举。



 

#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<vector>#include<cctype>#include<set>#include<map>#include<queue>#include<stack>#include<iomanip>#include<sstream>#include<limits>#define ll long long#define inf 0x3f3f3f3fusing namespace std;const int maxn = 1e2+10;const int maxm = 1e7+10;const int MOD = 1e9+7;ll a[maxn];ll Abs(ll x){return x>=0?x:-x;}int main(){#ifdef LOCALfreopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);//freopen("output.txt","w",stdout);#endifios_base::sync_with_stdio(0);    int n;    while(cin>>n && n)    {         for(int i = 0; i < n; i++) cin>>a[i];         map<ll,ll> mp;         pair<ll, ll> Min(Abs(a[0]),1);         for(int i = 1; i < 1 << (n/2); i++)         {             ll sum = 0,num = 0;             for(int j = 0; j < n/2; j++)                if ((i>>j) & 1) sum += a[j],num++;             Min = min(Min,make_pair(Abs(sum),num));             map<ll,ll>::iterator it = mp.find(sum);             if (it != mp.end()) it->second = min(it->second,num);                else mp[sum] = num;         }         for(int i = 1; i < 1 << (n-n/2); i++)         {             ll sum = 0,num = 0;             for(int j = 0; j < n-n/2; j++)                if ((i>>j) & 1) sum += a[j+n/2],num++;             Min = min(Min,make_pair(Abs(sum),num));             map<ll,ll>::iterator it = mp.lower_bound(-sum);             if(it != mp.end())Min = min(Min,make_pair(Abs(sum+it->first),num+it->second));if(it != mp.begin())            {--it;Min = min(Min,make_pair(Abs(sum+it->first),num+it->second));}         }        cout<<Min.first<<" "<<Min.second<<endl;    }    return 0;}

  

0 0
原创粉丝点击