【题解】愤怒的牛

题目来源:洛谷

题目描述

农夫约翰搭建了一间有N间牛舍的小屋。牛舍排在一条线上,第i号牛舍在Xi的位置。但是他的M头牛对小屋很不满意,因此经常相互攻击。约翰为了防止牛之间相互伤害,因此决定把每头牛都放在离其他牛尽可能远的牛舍。求最近的两头牛之间距离的最大值。

输入格式: t – 表示有t组数据,每组数据都由下面格式的数据构成。

第1行: 两个用空格隔开的整数: N和C
第2到n+1行: 每行一个整数xi
输出格式: 每组输出一个整数: 最近两头牛之间距离的最大值.

输入样例

1
5 3
1
2
8
4
9

输出样例

3

思路

类似的最大值最小化或者最小值最大化问题,通常用二分法就可以很好地解决。

设C(d)表示可以安排牛的位置,并使得最近的两头牛的距离不下于d

那么问题转换为求满足C(d)的最大的d,另外,最近的间距不小于d也可以看成是所有牛的间距都不小于d,因此就可以用C(d)表示可以安排牛的位置。并使得任意的两头牛的距离不小于d。

对这个问题的判断,使用贪心法便可非常容易地求解

  1. 对牛舍的位置x进行排序
  2. 把第一头牛放入x0的牛舍
  3. 如果第i头牛放入了xj间牛舍,则第i+1头牛就要放入满足 xj+d<=xk的最小的牛舍xk中

对x的排序只需在最开始时进行一次就可以了,每一次判断对每头牛最多进行一次处理,因此算法的时间复杂度是O(n logn)

code

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int t,n,m,a[N];
bool check(int mid) //判断这个距离可不可行 
{
    
    
	int cow=1,now=1; //cow:放的牛的数量 now:当前位置
	for (int i=1;i<=n;i++)
	{
    
    
		if (now+mid>a[i]) continue; //这个a[i](小屋)按照当前的距离来算放不了牛 
		cow++; //放得了的话牛的数量就++ 
		if (cow>=m) return true; //当前方案可行,直接返回true 
		now=a[i]; //记得更新当前位置
	}
	return false; 
}
int cut(int l,int r) //二分 
{
    
    
	int anss;
	while (l<=r)
	{
    
    
		int mid=(l+r)>>1; //">>1"的意思就是除以2	
		if (check(mid)==true) anss=mid,l=mid+1;
		else r=mid-1;
	}
	return anss;
}
void init()
{
    
    
	scanf("%d",&t);
	for (int i=1;i<=t;i++)
	{
    
    
		scanf("%d%d",&n,&m);
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	    sort(a+1,a+1+n);
	    cout<<cut(a[1],a[n])<<endl;
	}
}

int main()
{
    
    
	init();	
	return 0;	
}

猜你喜欢

转载自blog.csdn.net/weixin_45485187/article/details/102933419
今日推荐