1. 程式人生 > >HDU The Frog's Games(二分列舉)

HDU The Frog's Games(二分列舉)

問題簡述

給定一條河的寬度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;
}