qwb与李主席 状压+二分

来源:互联网 发布:胜任力测评软件 编辑:程序博客网 时间:2024/06/02 16:26

Description

qwb和李主席打算平分一堆宝藏,他们想确保分配公平,可惜他们都太懒了,你能帮助他们嘛?

Input

输入包含多组测试数据,处理到文件结束。

每组测试数据的第一行是一个正整数N(0 <= N <=36 )表示物品的总个数.。

接下来输入N个浮点数(最多精确到分),表示每个物品的价值V(0 < V <= 1e9)。

Output

对于每组测试数据,输出能够使qwb和李主席各自所得到的物品的总价值之差的最小值(精确到分),每组测试数据输出占一行。

Sample Input
3 0.01 0.1 1
2 1 1

Sample Output
0.89
0.00

HINT

首先年轻的我会想到dp,可能因为n很小 v很大,所以 背包是不可行的,只能用二分查找后者dfs。
对,因为是只有两个人,所以你会想到枚举一个,再二分sum/2-前面的是完全可行的。

因为数据范围是 36 单纯的状压肯定会超时。
然后我们可以想到一个人拿东西可能全在左边拿,或者全在右边拿。或者既在左边又在中间拿,对,说了和没说是一样的。但是这个揭露一个关键点,可以把这个东西枚举一边,二分另一边。所以就简单了,而且一边进行18个进行状压枚举,完全可以把所有的状态都弄出来。然后枚举一边,再二分另一边得到最正确的结果。
第一个坑点,因为是浮点数,要求精度比较高,精确到两位后会到11位,可以用long double,也可以化为 longlong 化成整型,因为后面要进行/2,所以200就很完美了。另一个点是 求两边相差最小,abs(sum-2(一个人的物品价值就好))

#include <bits/stdc++.h>using namespace std;typedef long long ll;ll a[1<<18],b[1<<18],c[1<<18],d[1<<18];void gao(ll g[],ll h[],int n){    ll gg=1<<n;    for(int i=0;i<gg;i++)    {        for(int j=0;j<n;j++)        {            if(i&(1<<j))                 h[i]+=g[j];        }    }}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {    ll cnta=0,cntb=0;    ll sum=0;    for(int i=0;i<n;i++)    {        double x;        scanf("%lf",&x);        ll y=round(x*200);        sum+=y;        if(i<=n/2) c[cnta++]=y;        else d[cntb++]=y;    }    gao(c,a,cnta);    gao(d,b,cntb);    cnta=(1<<cnta);    cntb=(1<<cntb);    sort(a,a+cnta);    ll minn=1e18;    for(int i=0;i<cntb;i++)    {        int pos=lower_bound(a,a+cnta,sum/2-b[i])-a;        minn=min(minn,abs(sum-2*(b[i]+a[pos])));        if(pos>=1) minn=min(minn,abs(sum-2*(b[i]+a[pos-1])));    }    printf("%.2f\n",minn*1.0/200 );    }}
原创粉丝点击