C++-跳石头 解题思路

【Horn Studio】编程专栏: 抢气球  解题思路

题目

题目描述

一年一度的“跳石头”比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有NN块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走MM块岩石(不能移走起点和终点的岩石)。

输入

第一行包含三个整数L,M,NL,M,N,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会最多移走的岩石数。保证L≥1L≥1且N≥M≥0N≥M≥0 。
接下来NN行,每行一个整数,第ii行的整数DiDi,表示第ii块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个出现在同一个位置。

输出

一个整数,即最短跳跃距离的最大值。

样例输入 复制

25 5 2  2 11 14 17  21

样例输出 复制

4

提示

对于20%的数据,
0≤M≤N≤100≤M≤N≤10
对于50%的数据,
0≤M≤N≤1000≤M≤N≤100
对于100%的数据,
0≤M≤N≤50,000,1≤L≤1,000,000,00000≤M≤N≤50,000,1≤L≤1,000,000,0000

来源

思路

这道题跟二分一样,从起点出发,先选定一段距离mid,若前面的石头B与你所站着的石头A的距离小于mid,就把B搬掉,记录一下;如果不,就把B留下,再跳到石头B上。照这个步骤多次循环后,如果搬掉的石头多了,就把距离mid定小点;如果少了,就把mid定大点。,很简单。直接考虑问题比较困难。我们首先考虑另一个问题,如果给定一个距离d,问至少要移走多少石头才能满足石头之间的最小距离不小于d?对于这个问题,答案就很简单了。从左岸开始,移走它小于d的所有石头,再往后跳一步,循环往复。就解决了!

我们同样需要一个判断,大概就是如下:

bool check(int x) {     int last = 0, cnt = 0;     for (int i = 1; i <= n; i++) {         if (a[i] - last < x)             cnt++;         else             last = a[i];     }     if (cnt > m)         return false;     return true; }

代码

#include <bits/stdc++.h> using namespace std; int a[50010], n, m, L, ans;  bool check(int x) {     int last = 0, cnt = 0;     for (int i = 1; i <= n; i++) {         if (a[i] - last < x)             cnt++;         else             last = a[i];     }     if (cnt > m)         return false;     return true; }  int main() {     cin >> L >> n >> m;     for (int i = 1; i <= n; i++)         cin >> a[i];     a[n + 1] = L;     int l = 0, r = L;     while (l <= r) {         int mid = (l + r) / 2;         if (check(mid)) {             ans = mid;             l = mid + 1;         } else             r = mid - 1;     }     cout << ans;      return 0; }

彩蛋

……这是哪?