二分法 ----- 跳石头

跳石头

跳石头
在这里插入图片描述
首先这是一道二分答案的题目

在这道题目的时候,我们先学习了解一下二分法,会的老铁可以跳过直接看后面的题解(下面将分为两种):

朴素二分(简单)

时间复杂度:O(logN)

while (left <= right)//这里要=!!!,因为当left=right时;待查区间为一个数时也要判断是否符合目标值,循环的结束条件是left>right
{
	int mid = left + (right - left) / 2;//优化,防止溢出
	if (……)
	{
		left = mid + 1;
	}
	else if (……)
	{
		right = mid - 1;
	}
	else
		return ……;
}

我的草稿图,可以参考一下(有点乱不要介意哈):
在这里插入图片描述

二分模板(万能,但是细节)

时间复杂度:O(logN)

//查找区间左端点的模板
while (left < right)
{
	int mid = left + (right - left) / 2;
	if (……) left = mid + 1;
	else right = mid;
}
//查找区间右端点的模板
while
{
	int mid = left + (right - left + 1) / 2;
	if (……) left = mid;
	else right = mid - 1;//记忆:有-1上面求中点就要+1
}

这里就简单展示一下模板,想要深入了解的看后后面其他博客哈
这里也简单展示一下草稿:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

接着进入正题:

1.首先是总体框架思想:
我们要移走石头,移走后最大距离为:
左边界:l = 1;(题目一说L>=1)
右边界:r = L;(终点)


然后我们就要利用这两个边界进行二分(朴素二分就行)出一个最大的距离
然后根据二分出来的距离通过check()函数检查是否合法
如果合法:先更新为最新结果,再进行二分,看是否有合法的更大的距离;
如果不合法:返回上次最大的合法距离,结束!

2.接着是check()函数的思想:
通过定义一个:
count(用来统计能移走多少石头,最后和我们一开始输入要求移走最多的石头m进行比较,看是否合法)
pos(一开始定义为0,即为起点,利用arr[i] - pos 记录每块石头之间的距离,并且每次更新pos到下一个位置)
最后判断是否合法,是否合法在上面描述了。

下面是AC的代码~

#include <iostream>
using namespace std;
int L,n,m;
int arr[50001];
//check函数用来判断该距离是否合法
bool check(int x)
{
    int count = 0;//该距离能移走多少石头
    int pos = 0;
    for(int i = 1; i <= n; i++)
    {
        if(arr[i] - pos < x) count++;//小于我们规定的距离,移走石头
        else pos = arr[i];
    }
    return count <= m;
}
int main()
{
    cin >> L >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        cin >> arr[i];
    }
    n++;
    arr[n] = L;//记录终点的位置,check函数里面要用到
    //利用二分法得出一个距离,再利用check()函数判断是否合法
    int l = 1;
    int r = L;
    int ret = 0;
    //求一个点用朴素二分,求区间采用区间二分,本题用是为了二分出一个距离,用朴素二分
    while(l <= r)
    {
        int mid = l + (r - l)/2;
        if(check(mid))
        {
            l = mid + 1;
            ret = mid;
        }
        else r = mid - 1;
    }
    cout << ret << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值