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 );
}
}