7.10 二分-跳石头游戏(二分答案)

今天为大家讲解一道我刚刚做的二分题目,重点在于理解以及考虑特殊情况。

题目描述  

  每逢过年,奶牛们玩跳石头游戏。这个游戏在一条笔直的河上进行。河上两个石头被作为起点和终点,

它们之间的距离为L(1≤L≤10)。还有N(0≤N≤50000)个 石头放置在这两个石头之间,每个石头距离起点都有

一个独一无二的整数距离D(0<D<L)。

  游戏进行的时候,奶牛们从起点开始,依次跳到每一个相邻的石头上,最终到达终点。约翰对自己的

奶牛很有信心。他每年都到场观看这奶牛们的游戏。今年,约翰终于不耐这个游戏的无聊,打算做一些手

脚,好让别的农夫的奶牛出丑。他打算除掉M(0≤M≤N)个石头,使任意两个石头间的最短距离变得尽量大。

这样,别人家的奶牛就很有可能失蹄了。

  请计算,采取最佳方案移除石头之后,最短距离是多少。注意,约翰不能移除起点和终点的石头。

输入说明


第1行输入L,N,M。接下来N行,每行一个整数表示一个石头的位置


输出说明


移除石头后的最短距离


输入样例

25 5 2

2

14

11

21 

17

输出样例:

4

样例说明:

  移除之前,最短距离在位置2的石头和起点之间;移除位置2和14两个石头后,最短距离变成17和21或

21和25之间的4

题解代码:

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int l,n,m,a[50011];
bool check(int mid){//函数用于测试最短距离为mid时需要除去的石头数量
 int last=0,tot=0;
 for(int i=1;i<=n;i++){
  if(a[i]-a[last]<mid){
   tot++;
   if(tot>m){
    return false;//说明当前mid偏大
   }
  }
  else{
   last=i;
  }
 }
 return true;//当前tot<=m,mid偏小
}
int main(){
// freopen("past_river.in","r",stdin);
 scanf("%d%d%d",&l,&n,&m);
 for(int i=1;i<=n;i++){
  scanf("%d",&a[i]);
 }
 
 a[++n]=l;
 sort(a,a+n+1);
 /*
 for(int i=1;i<=n;i++){
  printf("%d ",a[i]);
 }printf("\n");
 */
 int l1=0,ans;
 int r=l;
 
 while(l1<=r){
  int mid=(l1+r)/2;
 // printf("%d\n",mid);
  if(check(mid)){//mid偏小
   ans=mid;
   l1=mid+1;
  }
  else{
   r=mid-1;//mid偏大
  }
 }
 printf("%d\n",ans);
 
 return 0;
}
 
题解思路:
  设置a[]数组来依次表示各个石头与起点间的距离,a[n+1]表示终点与起点的距离, l设为河的长度,将数组与起点距离按由近到远进行排序。
1.设置一个bool型的check函数,判断最短距离为mid时应移去多少块石头。
函数中,设移除数量为tot,tot>m时说明mid过大,返回false;tot<=m时,说明mid偏小,返回true
 

2.最短距离最长为l,用二分查找,while(l<=r)l,r来查找最短距离,取平均数mid,用函数check来判断mid的 值:

  1.返回true,说明mid小于或等于正确答案,将ans赋值为mid,l=mid-1;

  2.返回false,除去的石头过多,说明mid大于正确答案

注:在这里需要注意一种情况,很多同学习惯于使用while(l<r),l=mid,r=mid-1,但在这道题中,会陷入死循环

最终结果输出ans即为正确答案

猜你喜欢

转载自www.cnblogs.com/cxs070998/p/11163969.html
今日推荐