二分答案思路

此时有一个农夫睡觉t小时,有n堆香蕉,每堆香蕉的数量为a1,a2····an个,猴子需要在农夫睡觉的这段时间内把香蕉吃完。如果猴子把一堆香蕉吃完了但是所用时间并不是整数倍小时,余下的时间他会选择睡觉来把当前小时过完。问猴子赶在农夫醒来能吃完香蕉的最小速度是多少。

一般情况下,要使猴子能在农夫醒来之前把香蕉吃完应该是越快越好,但是这里又要最小速度,所以要找到所有符合条件的最小值,这就是二分答案的应用场景(注意,因为是利用二分进行查找,所以要查找的序列必须是单调的!)。 

思路:用二分进行查找,如果找到的元素符合条件的话继续向左(更小的速度)查找,如果不符合条件的话就向右查找(让速度大一点,至少保证能在有限时间内把香蕉给吃完)。最后的结果就是所能找到的最优的结果。

首先看主函数部分(二分)

int left=0,right=0,ans=1;
for(int i=1; i<=n; i++)
{
    if(a[i]>right)//确定右边界
        right=a[i];
}
while(left<=right)
{
	mid=left+((right-left)>>1)//位运算的计算方法,表示除以2并向下取整
	if(check(mid))
	{
		ans=mid;//如果符合条件就先记录下来,然后看一下有没有更优的
		right=mid-1;
	}
	else
		left=mid+1;//如果不符合条件就速度大一点
}
cout << ans; 

然后是check函数(用来判断此时的速度是否能在规定时间之内吃完香蕉)

bool check(int speed)
{
	double num=0;
	for(int i=1; i<=n; i++)
	{
		num+=ceil(a[i]*1.0/speed);
	}
	if(num>t) return false;
	return true;
}

这个check函数的目的是把猴子吃每一堆香蕉的时间都给加起来算一下总时间,如果此时所用的时间小于农夫睡觉的时间的话,那么就符合条件,返回true,否则的话不符合条件,返回false。

对于for循环里边的语句,我做一个解释: ceil里边转换成浮点数进行相除,目的是为了得到它真正所用的时间,避免向下取整,如果是1.5个小时的话,剩下0.5个小时猴子会选择睡觉来凑成2个小时,如果直接运算就会变成1个小时,答案就改变了。ceil是一个向上取整函数,只要是不满整个小时的都会算成整个小时,与题意相符。

 总结一下,首先二分答案范围中的元素必须是单调的,它的主函数部分负责控制查找的方向,如果符合条件就向更优的方向进行查找,如果不符合条件就先保证符合条件。其次check函数就是用来判断是否符合条件,这个需要根据题中的意思,对当前查找的这个元素值进行判断。

你可能感兴趣的:(算法)