一:核心步骤:

1.确定答案的范围:找到最小可能值(left)和最大可能值(right);

2.二分查找:在left和right里面进行二分查找,每次取中间值mid;

3.bool check函数:用于判断mid是否可行;

(1):如果check返回true,说明这个mid可能是答案,调整搜素范围找更优解

(2):如果check返回false,说明mid不对,调整搜索范围

4.调整搜索范围:

根据(3)中check函数返回的结果,如果返回true,则更新right为mid(寻找更小的答案),反之,如果返回false,则更新left为(mid+1)(更大的答案);

例题:P2678 [NOIP 2015 提高组] 跳石头 - 洛谷

二:P2678复盘:

条件梳理:

l:从起点到终点的距离;n:n块石头;m:最多移走m块石头;stones:存放每个石头距离的数组

1:check函数参数x:在移走不超过m个石头下,假设最短跳跃距离为x;

ps:check函数的判断逻辑:

(1):遍历每一块石头,计算这一块石头与前一块的距离,如果是第一块,就是与起点的距离;

(2):定义计数器count,用于记忆一共移走了多少块石头;

(3):如果距离小于判断参数x,则移走,count++;如果大于等于,则不做操作;

(4):如果移走的数量count大于m,则返回false,反之返回true;

2:定义l,n,m三个变量以及存储每一块石头距离的数组为全局变量,以便check函数操作;

3:在main函数里面对答案二分,其中左指针(左边界)为0(起点),右指针(右边界)为l(全长);

ps:在不越界的范围内:如果返回true,则缩小范围继续找更优解,如果返回false,则改变范围找符合的值;

附代码:

#include <bits/stdc++.h>
using namespace std;
vector<int> stones;
int l = 0, n = 0, m = 0;
// l:起点到终点的距离,n:石头数量;m:最多移走的石头数量
bool check(int x)
{
	int last = 0;// 初始化last为起点,for循环中从第一块石头减去起点开始
	int num = 0;// 初始化移走石头的数量
	for (int i = 0; i < n; i++) // 遍历每一块石头
	{
		if (stones[i] - last < x)
		{
			num++;
		}
		else
		{
			last = stones[i];
		}
		if (num > m)
			return false;
	}
	// 检查终点与最后一个岩石;
	if (l - last < x)
		num++;
	return num <= m;
}
int main()
{
	cin >> l >> n >> m;
	stones.resize(n);
	for (int i = 0; i < n; i++)
		cin >> stones[i];
	// 输入完毕,开始计算
	sort(stones.begin(), stones.end()); // 确定石头是按距离排序
	int left = 0, right = l;			// 初始化二分答案的左右边界
	// 左边界为起点,右边界为终点到起点的距离l;
	// 左右指针说明了答案可能的范围,最小为0,最大为l
	int ans = 0; // 初始化答案
	while (left <= right)
	{
		int mid = left + (right - left) / 2; // 计算中间值
		if (check(mid))
		{
			ans = mid;
			left = mid + 1;//比mid小的值一定符合,所以在更大值的范围里面找
		}
		else
		{
			right = mid - 1;//比mid更大的值一定不符合,所以在更小值的范围里找
		}
	}
	cout << ans << endl;
	return 0;
}

Logo

集算法之大成!助力oier实现梦想!

更多推荐