ZOJ2868【折半】

题意:
把一堆数分成两堆,使得两堆的差值最小。
思路:
先把一堆数分成两堆,然后用个set存一堆的所有组合,枚举第一堆的状态,二分查找第二堆接近half_value。

瞎说时间复杂度:O(2^17*34);
(代码来着某位神犇)

#include<iostream>
#include<set>
#include<queue>
#include<cstdio>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
using namespace std;
int n;
vector<int>a,b;
set<int>ss;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int i=0,x,ans=0;
        a.clear();b.clear();
        scanf("%d",&n);
        for(;i<n/2;i++)
        {
            scanf("%d",&x);ans+=x;
            a.push_back(x);
        }
        for(;i<n;i++)
        {
            scanf("%d",&x);ans+=x;
            b.push_back(x);
        }
        int half=ans/2,sum,res;
        int sz=b.size();
        int num=(1<<sz);
        ss.clear();
        for(i=0;i<num;i++)
        {
            sum=0;
            for(int p=0;p<sz;p++) if(i&(1<<p)) sum+=b[p];
            ss.insert(sum);
        }
        res=-10000000;
        sz=a.size();
        num=(1<<sz);
        set<int>::iterator it;
        for(i=0;i<num;i++)
        {
            sum=0;
            for(int p=0;p<sz;p++) if(i&(1<<p)) sum+=a[p];
            if(sum>half) continue;
            int diff=half-sum;
            it=ss.lower_bound(diff);
            if((*it)==diff)
            {
                res=half;
                break;
            }
            if(it==ss.begin()) continue;
            it--;
            if((sum+(*it))>res)
                res=sum+(*it);
        }
        res=ans-2*res;
        printf("%d
",res);
    }
    return 0;
}



原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6777415.html