1. 程式人生 > >POJ-3258青蛙過河--二分答案

POJ-3258青蛙過河--二分答案

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;
}