题目较难。题目大致题意为母牛要过河,起始位置为0,终止位置为L,中间有n个石头,在可以移开最多m(0<=m<=n)块石头的情况下,求最大的(石块间的最小距离)。
题目与poj3273相似。可对照poj3273结题报告分析,分析如下:
选定一个数x,按照任意石头之间距离不小于(即>=)x的原则分组(结合贪心算法分组),求得最小石头移开数。
1)若最小石头移开数大于m,则说明该数大了,要减小。
2)若最小石头移开数小于等于m,则说明满足题意。那么我们就求以求出这些数中最大的x
而x的范围为0——L,且f(x)单调递增,f(x)表示对于给定的最小间隔,最小石头移开数。故可以利用二分查找法求得满足f(x)<=m的最大x。
下面是程序: 328K+94MS
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#define Max 50010 // 最大个数
using namespace std;
int record[Max]; // 记录石头的位置
int L,n,m;
int main(){
scanf("%d%d%d",&L,&n,&m);
record[0]=0; // 起始位置为0
record[n+1]=L; // 结束位置为L
for(int i=1;i<=n;i++) // 输入石头位置
scanf("%d",&record[i]);
sort(record+1,record+1+n); //对石头位置进行升序排序
int left=0,right=L,mid; //0<=x<=L,二分法求解满足最少石头移开数f(x)<=m的最大x值
while(left<=right){
mid=(left+right)>>1;
int ans=0,Sum,Count=0;
// ans,Sum,Count依次表示从哪个石头开始检查、第i个石头与第ans个石头之间的距离、移开石头个数
for(int i=1;i<=n+1;i++){ // 贪心法求解对于给定的x,按照上述组合方式所需移开的最小石头个数,注意这里i循环到n+1,而不是n(想想为什么)
Sum=record[i]-record[ans];
if(Sum<mid) // 若距离小于mid,则说明要移开第i个石头
Count++; // 移开石头数增加
else{ // 否则 从 第 i 个石头开始重新检验
ans=i;
}
}
if(Count>m) //若最小移开石头数大于m,则说明该数大了,要减小
right=mid-1;
else
left=mid+1;//否则求出这些数中的最大值
}
printf("%d\n",right); //输出最大值
return 0;
}