HDU The Frog's Games(二分列舉)
阿新 • • 發佈:2018-11-04
問題簡述:
給定一條河的寬度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; }