二分答案刷题3

各位小伙伴们,如果有幸可以被你看到我的文章,是我的荣幸。近期我的小目标是争取一天分享一道题题解,当然可能有时候比较忙啦,尽量吧。题目的思路都是个人看法,不喜勿闷喔。新的一年希望大家都能找到好工作,过上自己满意的生活,希望我今年也能顺利找到好的实习、好的工作啦。废话不多说,上题目。

题目来源:[NOIP2015 提高组] 跳石头 - 洛谷​​​​​​
解题思路: 

突然觉得做专项练习挺好的,这个题目一看就是用二分答案求解,时间复杂度比较低。 这道题需要找到最大的最短跳跃距离,使得最多移走M块岩石之后,每一步的跳跃距离都不小于这个最短跳跃距离。具备单调性,满足二分答案的要求。(若对二分答案不熟悉的小伙伴,指路我的第一篇关于二分答案的内容二分答案刷题1-CSDN博客)

 解题步骤:

1、 确定判断条件check函数。判断当前岩石和上一个岩石的距离是否小于minDist,小于则移除当前岩石(注:这里的判断,需要把终点加入,因为N只包括非终点的跳跃距离,但到终点还有一段距离)

  • 对于每一个假设的最短跳跃距离 mid,使用 check 函数来验证是否可以通过移除至多 M 块岩石来满足这个跳跃距离。
  • 遍历所有岩石,计算在保证最短跳跃距离至少为 mid 的条件下需要移除的岩石数量。如果当前岩石与上一个岩石的距离小于 mid,则计划移除这块岩石,并增加 remove 计数器。
  • 如果移除的岩石数量不超过 M,则说明假设的跳跃距离是可行的;否则,不可行。

2、 用二分查找缩短查找时间,每次用mid作为最短跳跃距离,直到找到为止,返回ans。

  • 如果 check(mid) 返回 true,说明至少有一种方法可以在移除至多 M 块岩石的情况下,使每一步的跳跃距离都至少为 mid。因此,更新答案 ansmid,并尝试更大的跳跃距离(增加 low)。
  • 如果 check(mid) 返回 false,说明没有办法在移走至多 M 块岩石的情况下保持每一步的跳跃距离至少为 mid。因此,减少跳跃距离(减小 high)以寻找可能的更小跳跃距离。
#include
using namespace std;
#define maxn 50010
int a[maxn];
int N, M;
long long  L;
bool check(int minDist)
{
	int remove = 0, last = 0; //初始移动岩石块和上一个岩石
	for (int i = 1; i <= N+1; i++) //从1开始,因为0是起点,到N+1是因为包括终点
	{
		if (a[i] - last < minDist)
		{
			remove++;// 如果当前岩石和上一个岩石的距离小于minDist,则移除当前岩石
		}
		else
		{
			last = a[i]; // 否则,跳到当前岩石
		}
	}
	return remove <= M;  // 检查移除的岩石数量是否不超过M
}


int main()
{

	
	cin >> L >> N >> M;
	a[0] = 0; // 起点
	for (int i = 1; i <= N; i++)
	{
		cin >> a[i];
	}
	a[N + 1] = L;//终点

	int low = 0, high = L, mid, ans = 0;
	while (low <= high)
	{
		mid = low + (high - low) / 2;
		if (check(mid))
		{
			ans = mid;// 如果可以实现这个距离,则尝试更大的距离
			low = mid + 1;
		}
		else {
			high = mid - 1;// 如果不可以,则尝试更小的距离
		}
	}

	cout << ans << endl;
	return 0;
}

 

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