POJ-3258青蛙過河--二分答案
阿新 • • 發佈:2019-01-09
Description
有一條寬度為L(1≤L≤ 1,000,000)的河。河中間有N(0≤N≤20000)塊石頭,青蛙從河西岸經過這N個石塊後,順利跳到了河的東岸。設河中間每個石塊距離西岸的距離為Di(其中Di大於0小於L)。注意:Di是距離起始河岸的距離。
小明閒著沒事,想移掉河中間的M(0≤M≤N)個石塊,讓一些石塊之間的距離增大一點,好叫青蛙沒那麼容易跳到對岸。
由於移除M個石塊的方法有多種,所以在移除石塊之前,小明想知道如果他恰好移除河中M個石塊後,青蛙跳的最短距離的最大值可以達到是多少?(青蛙跳一段的距離:西岸與河中第一個石塊距離、河中相鄰石塊的距離、最後一個石塊與東岸的距離。青蛙每次都是從一個石塊跳到與它相鄰的下一個石塊)。
Input
多組輸入。第一行順序輸入L, N和M。接下來輸入N個正整數(不保證有序),表示N個石塊距離起始河岸的距離。
Output
對於組輸入,輸出移除M個石塊後,整個跳躍過程中最短距離的最大值。
Sample Input
25 5 2
2
14
11
21
17
Sample Output
4
Hint
在移除石塊之前,跳躍過程中的最小間距2(起點距第1個石塊)。移除距離起始岸為2和14的石塊後,最小間距就為4了。(0 – 11 – 17 – 21 – 25 )。
程式碼:
#include<iostream> #include<algorithm> using namespace std; const int size = 50002; int D[size],L,N,M; int minl,maxl, ans; bool Ok(int x) { int tot = 0,i = 0, t = 0; while (i<=N) { tot = D[i++]; while (i <= N && tot < x) {//不能小於x, tot小於列舉的x,必須合併 tot += D[i++]; t++;//拿掉一塊石頭,合併一次 } if (t > M) return 0;//要使用t次才能滿足答案為x的條件,超過了M,不符合等於M的條件,返回0 } //加上,這一句 //此時tot是最後幾塊合併的值,如果他小於列舉的答案x //且t==M(也就是你之前把可以拿去M塊石頭的機會都用光了), //這種情況tot為最小值,所以x不符合條件 if (tot < x && M == t) return 0; return 1; } void Binary() { int l = minl, r = maxl, m; while (l <= r) { m = (l+r)/2;// if (Ok(m)) l = m + 1, ans = m;/*繼續列舉更大的答案(最小值最大, 能夠越大盡量越大),並且記錄當前可行的答案 */ else r = m - 1;//列舉更小的答案 } } int main() { int i, j, k; //freopen("B.in","r",stdin); //freopen("tmp.out","w",stdout); while (scanf("%d%d%d",&L,&N,&M)!=EOF) { for (i = 0; i < N; i++) scanf("%d",&D[i]); sort(D,D+N);//排序,計算石頭之間的間距 D[N] = L;//最後塊(也就是對岸)距離起點的距離為L minl = maxl = ans = D[0]; for (i = N; i > 0; i--) { D[i] = D[i]-D[i-1];//求石頭間距 //printf("%d ",D[i]); //if (D[i] == 0) printf("AAA\n"); if (D[i]<minl) minl = D[i];//找出所有間距中的最小值 maxl += D[i];//最大間距就是Di之和,也就是L } Binary();//二分列舉答案 printf("%d\n",ans); } return 0; }