今天为大家讲解一道我刚刚做的二分题目,重点在于理解以及考虑特殊情况。
题目描述
每逢过年,奶牛们玩跳石头游戏。这个游戏在一条笔直的河上进行。河上两个石头被作为起点和终点,
它们之间的距离为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];
#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 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;
}
// 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即为正确答案