HDU The Frog's Games(二分枚举)

版权声明:wywwzjj https://blog.csdn.net/weixin_42348709/article/details/81360506

问题简述

给定一条河的宽度L、石头的数量n、青蛙最多能跳跃的数量m以及每块石头距离岸边的距离,求青蛙过河的最短步长。

问题分析

只需关注当前的“利益”,跳一步跨过的石头越多,用的总步数越少,自然满足题意。

对于这种最值问题,如果满足“单调性”,就可以直接用二分来做:

                           最值性问题    \rightarrow    判断性问题

二分的模板很容易,所以问题的关键转变为写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;
}

猜你喜欢

转载自blog.csdn.net/weixin_42348709/article/details/81360506