Aggressive cows--二分法思想

题目链接:2456 -- Aggressive cows

题目描述:

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000).

His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ wants to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

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

输入格式:

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

第1行: 两个用空格隔开的整数: N 和 C (2 <= N <= 100,000)  (2 <= C <= N)

第2到n+1行: 每行一个整数 xi   (0 <= xi <= 1,000,000,000)

输出格式:

每组输出一个整数: 最近两头牛之间距离的最大值.

示范样例:

输入 

5 3
1
2
8
4
9

输出

3

 

题目分析:  

我们先看一下输入输出样例:5间牛舍,3头奶牛,但是输入的牛舍数据不是规则排序的,因此我们应该先将其进行排序,得到1 2 4 8 9,然后易知两头奶牛之间的最近距离最大为3,此时3头奶牛的牛舍坐标分别为1,4,8或9。

由此看来我们在得到牛舍的位置数据时应该先对其进行排序,以便后续操作。

cin >> n >> c;//输入n座牛舍,c头奶牛
	for (int i = 0; i < n; i++) 
	{
		cin >> a[i];
	}
	sort(a, a + n);//排序从a[0]开始,到a[n-1]结束,按照从小到大的顺序排列

我们从1,000,000,000/c到1枚举虽然可行,但是枚举比较耗时,效率不够高,这时我们就要用到二分的思想来提高效率了。

首先对二分内容明确一下:对两头奶牛之间的最近距离进行二分。因为牛舍的位置已经按照从大到小的顺序排列好了,我们的二分区间即为【1,1,000,000,000/c】(因为两头奶牛之间的最近距离为1——牛舍数/奶牛数)时间复杂度为log (1,000,000,000/c)*n(下面会解释)

代码片段: 

 二分代码

void BinarySearch(int n, int c)//n为牛舍数,c为奶牛数
{
	int left = 0, right = a[n - 1] / c;//二分区间
	int mid = left + (right - left) / 2;//开始二分
	while (left <= right)
	{
		if (check(mid, a, n, c))//假设的最近距离不够大
		{
			left = mid + 1;
		}
		else
		{
			right = mid - 1;
		}
		mid = left + (right - left) / 2;//继续二分
	}
	cout << right << endl;
}

二分的区间为【1,1,000,000,000/c】,check函数是检查二分得到的假设的最近距离是否为最大,如果不够大的话证明此时在mid前面的数据都不够大,因此left变为mid+1,如果够大的话同理可得此时mid后面的数据都够大,因此right变为mid-1来寻找最近的距离。每次检查都要从(1——1,000,000,000/c)遍历,所以这道题二分的时间复杂度为log (1,000,000,000/c)*n。

check函数检查的代码:

bool check(int mid, int a[], int n, int c)//检查所假设的两头奶牛之间的最近距离是否为最大
{
	int count = 1;//初始一头奶牛
	int cur = a[0];//当前牛舍地址
	for (int i = 1; i < n; i++)//从第二头牛开始放
	{
		if (a[i] - cur >= mid)//当前牛舍可以放牛
		{
			count++;//假设放置的奶牛数量加一
			cur = a[i];//当前牛舍地址更改
		}
	}
	if (count >= c)//在给定的mid值下能够放下的牛的个数大于实际奶牛个数c,说明两头奶牛之间的最近距离不够大
	{
		return 1;
	}
	return 0;
}

如果两头奶牛之间的最近距离不够大返回true(1),否则返回false(0)。

整体代码: 

#include<iostream>
#include<algorithm>
using namespace std;
int a[100000] = { 0 };
bool check(int mid, int a[], int n, int c)//检查所假设的两头奶牛之间的最近距离是否为最大
{
	int count = 1;//初始一头奶牛
	int cur = a[0];//当前牛舍地址
	for (int i = 1; i < n; i++)//从第二头牛开始放
	{
		if (a[i] - cur >= mid)//当前牛舍可以放牛
		{
			count++;//假设放置的奶牛数量加一
			cur = a[i];//当前牛舍地址更改
		}
	}
	if (count >= c)//在给定的mid值下能够放下的牛的个数大于实际奶牛个数c,说明两头奶牛之间的最近距离不够大
	{
		return 1;
	}
	return 0;
}
void BinarySearch(int n, int c)
{
	int left = 0, right = a[n - 1] / c;//二分区间
	int mid = left + (right - left) / 2;
	while (left <= right)
	{
		if (check(mid, a, n, c))//假设的距离不够大
		{
			left = mid + 1;
		}
		else
		{
			right = mid - 1;
		}
		mid = left + (right - left) / 2;
	}
	cout << right << endl;
}
int main() 
{
	int n, c;
	cin >> n >> c;//首先输入n座牛舍和c头奶牛
	for (int i = 0; i < n; i++) 
	{
		cin >> a[i];
	}
	sort(a, a + n);//将牛舍排序
	BinarySearch(n,c);
	return 0;
}

二分加上贪心的思想

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值