二分查找---河中跳房子

每年奶牛们都要举办各种特殊版本的跳房子比赛,包括在河里从一个岩石跳到另一个岩石。这项激动人心的活动在一条长长的笔直河道中进行,在起点和离起点L远 (1 ≤ L ≤ 1,000,000,000) 的终点处均有一个岩石。在起点和终点之间,有 N (0 ≤ N ≤ 50,000) 个岩石,每个岩石与起点的距离分别为 Di (0 < Di < L)。
在比赛过程中,奶牛轮流从起点出发,尝试到达终点,每一步只能从一个岩石跳到另一个岩石。当然,实力不济的奶牛是没有办法完成目标的。
农夫约翰为他的奶牛们感到自豪并且年年都观看了这项比赛。但随着时间的推移,看着其他农夫的胆小奶牛们在相距很近的岩石之间缓慢前行,他感到非常厌烦。他计划移走一些岩石,使得从起点到终点的过程中,最短的跳跃距离最长。他可以移 走除起点和终点外 至多 M (0 ≤ M N ) 个岩石。
请帮助约翰确定移走这些岩石后, 最长可能的最短跳跃距离是多少?

输入
第一行包含三个整数L, N, M,相邻两个整数之间用单个空格隔开。
接下来N行,每行一个整数,表示每个岩石与起点的距离。岩石按与起点距离从近到远给出,且不会有两个岩石出现在同一个位置。
输出
一个整数,最长可能的最短跳跃距离。
样例输入
25 5 2211141721
样例输出
4
解法:
题目分析:
1.序列N中存放的是中间N个石头的位置,起止点的位置没有存储。
2.移除只能移除N中的M个石头,起止点的石头都不能动
3.牛一块石头挨一块的跳,不能连续跳石头。
思路:
1.假设最大的最小跳距离时D,那么和stone[i]距离小于D的时候都要被移除。
2.D的最小取值就是1,最大取值就是把N个石头全移走,直接从起始点调到终止点。
原始思路纠正。
int L,N,M;
cin>>L>>N>>M;
int stone[50010];
for(int i = 1 ;i<= N ;i++)
cin>>stone[i];
max_dis = L;//注意最后一跳,牛是直接跳过去的。
----------------------------------------------------------------
1.没有存起止点的位置
stone[0]=0,stone[N+1]=L
------------------------------------------------------------------
//1.统计两块石头间的最小距离,这个步骤可有可无
int l = 0,r = max_dis;
----------------------------------------------------------------
2.最小的距离至少是1,最大的距离时L
题目说的起止点是stone[0]和stone[N+1],不是stone[1]和stone[N],
后边这一组是可以移除的
l=0, r=L
------------------------------------------------------------------
while(l<=r)
{ D = (r+l)/2;
int start = 0;
total = 0;
----------------------------------------------------------------
3.这时候要从stone[1]一直分析到stone[N+1],把中间该移除
的石头全部移走。
问:题目明确说不能移走stone[N+1]呀?
如果stone[N+1]被移走,则说明它在某个D之内,也就是说这一跳与前边一块石头的距离小于D,而这与题目假设条件--D为最小跳距相矛盾;另一方面则,说明这个D过大,被移走的M过多。因此,系统需要把D往小调,直到令stone[N+1]与紧邻的最后一块石头的距离>=D。
------------------------------------------------------------------
for(int i = 1; i<N i<=N+1 ;i++) //题目明确规定是除起点和终点外的石头,
{
//从i+1开始找,只要和i的距离小于D,就必须移除。
if(stone[i]-stone[start]<D &&i!=N-1 )//终点外的石头,
total++;
else
start = i;
}
if(total>M) //说明D太大了,移除的石头太多了
R = D-1;
else
{
last_D = D;
L = D+1;
}
}

标准答案:
#include<iostream>
#include<math.h>
using namespace std;
int main()
{
int L,N,M;
cin>>L>>N>>M;
long stone[50010];
stone[0]=0;
for(int i = 1;i<=N;i++)
cin>>stone[i];
long max_dis = L;//注意最后一跳,牛是直接跳过去的。
//1.统计两块石头间的最小距离,这个步骤可有可无
long l = 1,r = L;
stone[N+1] = L;
//cout<<"r "<<r<<endl;
long last_D,D;
while(l<=r)
{ D = (r+l)/2;
int start = 0;
int total = 0;
for(int i = 1;i<=N+1;i++) //题目明确规定是除起点和终点外的石头,
{
//从i+1开始找,只要和i的距离小于D,就必须移除。
if(stone[i]-stone[start]<D)
{
total++;
}
else
start = i;
}
if(total>M) //说明D太大了,移除的石头太多了
r = D-1;
else
{
last_D = D;
//cout<<D<<endl;
l = D+1;
}
}
cout<<last_D;
}

猜你喜欢

转载自blog.csdn.net/cleanarea/article/details/78762003