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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值