好斗的牛(二分算法)

先使无序的xi值变为有序的,再采用二分法求解,别忘了排序。

描述
一农夫有一牛棚,该棚有N个(2 <= N <= 100,000)槽。各槽沿同一直线的位置分别是x1,…xi,xN(0 <= xi <= 1,000,000,000)。

他又有C(2 <= C <= N)头母牛,在一起会互相攻击。为了防止这些母牛相互伤害,农夫希望让每两头奶牛间距离D越大越好,但前提是所有牛都能被放下。求这个距离D。

输入
第1行:两个以空格分隔的整数:N和C
第2…N + 1行:第i + 1行包含整数停滞位置xi

输出
第1行:一个整数:最大最小距离

样例输入
5 3
1
2
8
4
9
样例输出
3

一、题目分析

问题很是绕口,概括起来就是,在能把所有牛都放在棚里的前提下,使得相邻最近两头牛间的距离D最大

显然D在0到 xN/C 之间,当D=xN/C时,C头牛之间的距离总和在间距相同时为xN。在这个区间内逐一枚举D是很低效的,对于区间问题,二分法是首先考虑的。当然,采用二分法前,要先使区间有序。

设left为二分区间左值,right为区间右值,先尝试D=left+(right-left)/2,如果该值满足条件,先保存该值,继续尝试更大的D,令left=D+1;如果该D已经不满足,则在小区间里进行二分,令right=D-1。


判断D是否满足条件的函数

bool isAnswer(int D)
{
	int last = 0; //记录上一个放奶牛的槽
	int cur = 1;  //当前准备放奶牛的槽
	int cnt = 1;  //成功放入奶牛的次数
	for ( cur = 1; cur < N; cur++)
	{
		if (X[cur] - X[last] >= D)
		{
			cnt++;
			last = cur;
		}
	}
	//放入奶牛的次数与牛的头数相等即满足条件
	return (cnt >= C) ? true : false;
}


二、源代码


//

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int N = 0, C = 0;
vector<int> X;

bool isAnswer(int D);

int main()
{

	cin >> N >> C;
	int n = 0;
	for (int i = 0; i < N; i++)
	{
		cin >> n;
		X.push_back(n);
	}		
	sort(X.begin(),X.end()); //数据有序才能二分
	
	int left = 0, right = X[N-1] / C;
	int ans = 0;
	while (left<=right)
	{
		int D = left + (right - left) / 2;
		if (isAnswer(D))
		{
			ans = D;
			left = D + 1;
		}
		else right = D - 1;
	}
	cout << ans << endl;

	return 0;
}

bool isAnswer(int D)
{
	int last = 0; //记录上一个放奶牛的槽
	int cur = 1;  //当前准备放奶牛的槽
	int cnt = 1;  //成功放入奶牛的次数
	for ( cur = 1; cur < N; cur++)
	{
		if (X[cur] - X[last] >= D)
		{
			cnt++;
			last = cur;
		}
	}
	//放入奶牛的次数与牛的头数相等即满足条件
	return (cnt >= C) ? true : false;
}


题目挺简单的,多注意细节。比如我在输入xi的值时,开始用了个while(N- -),但同时我把N定义成了全局变量,导致计算错误。还有就是别混淆了距离和下标,本题是用距离在二分。

发布了13 篇原创文章 · 获赞 7 · 访问量 594

猜你喜欢

转载自blog.csdn.net/hejnhong/article/details/104591468