[二分算法] c++ 跳石头比赛

跳石头比赛
时间限制:C/C++ 1000MS
内存限制:C/C++ 64MB
描述

每年奶牛们都要举办各种特殊版本的跳石头比赛,包括在河里从一个岩石跳到另一个岩石。这项激动人心的活动在一条长长的笔直河道中进行,在起点和离起点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
用例输出 1 

4

提示

在移除位于2和14的两个岩石之后,最短跳跃距离为4(从17到21或从21到25)。

要求:使用二分算法

这题我会,但我找不到代码了,只好先参考一下博客园和洛谷了,代码如下:

#include<bits/stdc++.h> 
using namespace std;
int n,a[2000000],m,l,s,num,mid,ans;
int half(int x)
{
    s=0,num=0;
    for(int i=1;i<=n;i++)
        {
        
        if(a[i]-s<x) num++; 
        else s=a[i];
        }
        if(num>m) return 0;
        return 1;
}
int main()
{
    cin>>l>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    a[n+1]=l;
    int r=l,l=0;
    while(l<=r)
    {
         mid=(l+r)/2;
         if(half(mid))
            {
              l=mid+1; 
              ans=mid; 
            }
        else r=mid-1; 
    }
    cout<<ans<<endl;
    return 0;
}
  • 帮你找了个相似的问题, 你可以看下: https://ask.csdn.net/questions/7452941
  • 以下回答由chatgpt基于相关博客总结生成:

    首先,我们需要明确题目的要求。题目要求找到最长的跳跃距离,使得约翰最多可以移除M个岩石。那么我们可以将这个问题转化为一个求解最长跳跃距离的最小化问题。

    我们可以使用二分算法来解决这个问题。首先,我们需要确定跳跃距离的范围,最短跳跃距离至少为1,而最长跳跃距离为起点到终点的距离L。然后,在这个距离范围内进行二分查找。

    每次二分查找时,我们假设当前的跳跃距离为mid,然后计算约翰最多可以移除多少个岩石,使得从起点到终点的跳跃距离都大于等于mid。具体步骤如下:

    1. 定义二分查找的左边界left为1,右边界right为L。
    2. 当left小于等于right时,执行以下步骤:
    3. 计算mid=(left+right)/2,表示当前的跳跃距离。
    4. 初始化移除岩石的数量为0。
    5. 遍历每个岩石的距离,如果该岩石与前一个岩石的距离大于等于mid,则可以移除该岩石,移除岩石的数量加1。
    6. 如果移除岩石的数量大于M,表示当前的跳跃距离太大,应该在左半边寻找更小的距离,更新右边界right为mid-1。
    7. 否则,表示当前的跳跃距离符合要求,但还有可能找到更长的距离,应该在右半边继续寻找,更新左边界left为mid+1。
    8. 返回最长可能的最短跳跃距离,即right。

    以下是具体的代码实现:

    #include <iostream>
    #include <vector>
    using namespace std;
    
    bool canRemoveStones(vector<int>& stones, int distance, int maxRemoves) {
        int n = stones.size();
        int removes = 0;
        int lastStone = stones[0];
        for (int i = 1; i < n; i++) {
            if (stones[i] - lastStone < distance) {
                removes++;
            } else {
                lastStone = stones[i];
            }
            if (removes > maxRemoves) {
                return false;
            }
        }
        return true;
    }
    
    int binarySearch(vector<int>& stones, int left, int right, int maxRemoves) {
        int result = 0;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (canRemoveStones(stones, mid, maxRemoves)) {
                result = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return result;
    }
    
    int main() {
        int L, N, M;
        cin >> L >> N >> M;
    
        vector<int> stones(N);
        for (int i = 0; i < N; i++) {
            cin >> stones[i];
        }
    
        int answer = binarySearch(stones, 1, L, M);
        cout << answer << endl;
    
        return 0;
    }
    

    这样,我们就可以使用二分算法解决C++跳石头比赛的问题了。代码中的canRemoveStones函数用于判断约翰最多可以移除多少个岩石,使得从起点到终点的跳跃距离都大于等于distance。binarySearch函数用于进行二分查找,找到最长可能的最短跳跃距离。

    希望能帮到你!如果还有其他问题,请随时提问。