版权声明:wywwzjj https://blog.csdn.net/weixin_42348709/article/details/81360506
问题简述:
给定一条河的宽度L、石头的数量n、青蛙最多能跳跃的数量m以及每块石头距离岸边的距离,求青蛙过河的最短步长。
问题分析:
只需关注当前的“利益”,跳一步跨过的石头越多,用的总步数越少,自然满足题意。
对于这种最值问题,如果满足“单调性”,就可以直接用二分来做:
最值性问题 判断性问题
二分的模板很容易,所以问题的关键转变为写check()函数。
参考代码
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
typedef long long ll;
typedef long double ld;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
const double PI=acos(-1.0);
const int MAXN=1e6+5;
const int MOD=1e9+7;
int a[MAXN] = {0};
int l,n,m;
bool check(int r) {
int cnt = 0;
for(int i = 1; i < n+2; i++) {
int dist = a[i] - a[i-1];//dist为前后两个石头间的距离
if(r < dist) return false;//如果遇到哪一步跨不过去,直接返回假(必要条件)
int cur = i;//暂存一下当前的位置
while(1) {
i++;if(i > n+1) break;//防止数组越界
dist = a[i] - a[cur-1];//dist为离当前石头的距离
if(r < dist) {i--;break;}//贪心策略:单步跨过的石头越多,过河的总步数必然会越少
}
cnt++;
}
return cnt <= m;//判断步数是否符合条件
}
int main() {
while(~scanf("%d%d%d", &l, &n, &m)) {
rep(j,1,n+1) sf("%d",&a[j]);//从1开始计数
a[n+1] = l;//将最后一个位置存到数组末尾
sort(a,a+n+2);
int lo = 0,hi = l;
while(lo < hi) {//二分的套路,只需要注意死循环
int mid = (hi + lo) / 2;
if(check(mid)) {
hi = mid;
} else lo = mid + 1;
}
pf("%d\n",hi);//hi与lo是相等的,随便输出哪一个
}
return 0;
}