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; }
彩蛋
……这是哪?