贪心与分治,作为一个较大的专题,确实应当受到重视。
而二分又是贪心中较为好用且关键的一个方法
思路:均分蛋糕问题,每个人都必须吃一个整的蛋糕,意思就是不能多个蛋糕累加,现如果希望蛋糕最大。
原来的想法是贪心,建立新数据结构存储蛋糕并不断维护。每个人都挑目前可能吃到的最大的蛋糕,然后与原来的人均分该蛋糕。按照这种思路一直走下去,优先队列优化时间,并单独记录最小蛋糕用于最终输出,将时间复杂度降了下来,不过却发现该算法思路不周,因为并不能知道每个蛋糕实际分给多少人,均分可能会导致蛋糕被破坏
分析发现,以这种方法,会使该蛋糕大小大打折扣,单步贪心会是结果被局限化,导致搜索出局部最优,于是会造成不合理而隔离了最优答案。要是想寻找到最优答案,还是需要二分来实现
分析:以控制误差1e-5为二分左端点lef,最大蛋糕为二分右端点rig,判断mid【=(rig+lef)/2】处蛋糕所能分给的人数,分界点(即刚好够f+1个人吃)为左端点维护处,左右端点差小于控制误差作为循环结束标志,最终实现二分查找
/*
Author:Owen_Q
*/
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+10;
const double pi = 3.14159265359;
double cake[maxn];
int f,n;
long long ownnum(double area)
{
long long sum = 0;
for(int i=0;i<n;i++)
{
sum += (long long)((cake[i] + 1e-9) / area);
}
return sum;
}
int main()
{
int m;
while(scanf("%d",&m)!=EOF)
{
while(m--)
{
scanf("%d%d",&n,&f);
double lef,rig,mid;
lef = 1e-5;
rig = 0;
for(int i=0;i<n;i++)
{
double ri;
scanf("%lf",&ri);
cake[i] = pi * ri * ri;
if(cake[i]>rig)
{
rig = cake[i];
}
}
while(rig-lef>=1e-5)
{
mid = (rig + lef) / 2.0;
//cout << ownnum(mid) << "*" <<lef << "*"<< mid <<"*"<<rig<< endl;
if(ownnum(mid)>=f+1)
{
lef = mid;
}
else
{
rig = mid;
}
}
printf("%.4f\n",mid);
}
}
}
/*单步贪心WA
typedef struct CAKE
{
double area;
int num;
double perarea;
double nexarea;
}Cake;
struct cmp
{
bool operator ()(const Cake &a,const Cake &b)const
{
if(a.nexarea<b.nexarea)
{
return true;
}
else
{
return false;
}
}
};
priority_queue <Cake,vector<Cake>,cmp> c;
int main()
{
int m;
while(scanf("%d",&m)!=EOF)
{
while(m--)
{
int f,n;
scanf("%d%d",&n,&f);
while(!c.empty())
{
c.pop();
}
double minarea = 1e10;
for(int i=0;i<n;i++)
{
double ri;
Cake tempcake;
scanf("%lf",&ri);
tempcake.area = pi * ri * ri;
tempcake.num = 1;
tempcake.perarea = tempcake.area / (double)(tempcake.num);
tempcake.nexarea = tempcake.area / (double)(tempcake.num + 1);
if(tempcake.perarea < minarea)
{
minarea = tempcake.perarea;
}
c.push(tempcake);
}
//cout << c.top().perarea;
if(n>=(f+1))
{
while(f--)
{
c.pop();
}
printf("%.4f\n",c.top().perarea);
}
else
{
for(int i=0;i<=f-n;i++)
{
Cake maxcake = c.top();
c.pop();
maxcake.num++;
maxcake.perarea = maxcake.nexarea;
maxcake.nexarea = maxcake.area / (double)(maxcake.num + 1);
if(maxcake.perarea < minarea)
{
minarea = maxcake.perarea;
}
c.push(maxcake);
}
printf("%.4f\n",minarea);
}
}
}
return 0;
}*/