河中跳房子(详解)

题目描述
每年奶牛们都要举办各种特殊版本的跳房子比赛,包括在河里从一个岩石跳到另一个岩石。这项激动人心的活动在一条长长的笔直河道中进行,在起点和离起点L远 (1 ≤ L≤ 1,000,000,000) 的终点处均有一个岩石。在起点和终点之间,有N (0 ≤ N ≤ 50,000) 个岩石,每个岩石与起点的距离分别为Di (0 < Di < L)。

在比赛过程中,奶牛轮流从起点出发,尝试到达终点,每一步只能从一个岩石跳到另一个岩石。当然,实力不济的奶牛是没有办法完成目标的。

农夫约翰为他的奶牛们感到自豪并且年年都观看了这项比赛。但随着时间的推移,看着其他农夫的胆小奶牛们在相距很近的岩石之间缓慢前行,他感到非常厌烦。他计划移走一些岩石,使得从起点到终点的过程中,最短的跳跃距离最长。他可以移走除起点和终点外的至多M (0 ≤ M ≤ N) 个岩石。

请帮助约翰确定移走这些岩石后,最长可能的最短跳跃距离是多少?

输入
第一行包含三个整数L, N, M,相邻两个整数之间用单个空格隔开。

接下来N行,每行一个整数,表示每个岩石与起点的距离。岩石按与起点距离从近到远给出,且不会有两个岩石出现在同一个位置。

输出
一个整数,最长可能的最短跳跃距离。

样例
输入数据 1
25 5 2
2
11
14
17
21
Copy
输出数据 1
4
Copy
提示
在移除位于2和14的两个岩石之后,最短跳跃距离为4(从17到21或从21到25)。

来源
一本通在线评测


分析

第一步、问题求解与思维方式

实现跳跃问题,该问题要求在给定的河道中找到可以挪走的石头,并计算从起点到石头的最短跳跃距离。首先,需要画出一个给定长度的河道,然后根据样例找出可以挪走的石头。接下来,通过遍历河道中的每一块石头,判断哪些石头可以被挪走,并计算从起点到该石头的最短跳跃距离。最后,输出跳跃距离的最小值。

第二步、解决搬石头问题

通过二分查找来解决搬石头问题。首先,定义了数据范围,包括河流长度L、石头的数量N和搬走的石头数目M。然后,按照顺序读取输入数据,先读取河流长度,再读取石头的数量,最后读取搬走的石头数目。在处理每个石头时,从起点开始判断,直到找到满足条件的石头。这样的处理方式对于后续的跳石头或判断会更加简单。

第三步、解决石头跳跃问题的算法解析

首先,将河中的每一块石头读入,然后进行求解。在求解过程中,需要确定最短跳跃距离的范围,以及最大跳跃距离的范围。通过讨论,得出最短跳跃距离为1,最大跳跃距离为L。接下来,讨论了如何进行判断,以及在判断过程中需要注意的问题。最后,通过实例分析,发现了一个关于五块石头的问题,即最多只能搬几块石头。

第四步、解决如何通过搬石头满足条件的问题

首先,我们需要找到满足条件的最后一个值,然后判断它是否是最大或最小跳跃距离。如果满足条件,那么我们需要返回第一个不满足条件的值。接下来,我们开始逐个检查每个石头的移动情况。如果跳的距离大于等于X,则代表这块石头可以留着;否则,我们需要将这块石头挪走。最后,我们将循环变量更新,并继续查找下一个满足条件的值。

第五步、解决石头挪移问题

首先,通过减法计算,当当前石头距离起点小于X时,说明需要挪走一块石头。接下来,讨论了如何判断哪一块石头需要被搬走。在计算过程中,发现第二块石头的距离已经大于等于五,因此需要搬走一块石头。在判断哪一块石头需要被搬走时,发现是第二块石头的距离,而不是上一块没有搬走的石头的位置。最后,讨论了如何记录上一块石头的位置,以便在下一轮石头移动时使用。

如何用S来记录当前已经跳到哪块石头,以及如何计算距离的方法

首先,通过D减去零,判断上一块石头是否还在,如果不在,则加一。然后,用S减去上一块石头的位置,判断距离是否大于等于X。如果满足条件,则跳到下一块石头。在循环中,每次跳完一个石头后,都会用D减去零,判断下一块石头的起点是否还在,如果不在,则加一。最后,通过count加一,判断当前的S是否等于17,如果等于17,则跳到最后一块石头,否则继续循环。


代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[50001],l,n,m;
int judge(int d){
    int i=0,start=0,ans=0;
    for(i=1;i<=n+1;i++){
        if(a[i]-start<d)
            ans++;
        else
            start=a[i];
    }
    if(ans>m)
        return 0;
    else
        return 1;
 
}
int main(){
    cin>>l>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    a[n+1]=l;
    sort(a+1,a+n+2);
    int low=1,high=l;
    int ans;
    while(low<=high){
        int mid=(low+high)/2;
        if(judge(mid)){
            ans=mid;
            low=mid+1;
        }
        else{
            high=mid-1;
        }
    }
    cout<<ans<<endl;
    return 0;
}

给个赞和关注吧

  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值