1. 程式人生 > >進擊的奶牛

進擊的奶牛

題面(from luogu)
進擊的奶牛
Farmer John建造了一個有N(2<=N<=100,000)個隔間的牛棚,這些隔間分佈在一條直線上,座標是x1,…,xN (0<=xi<=1,000,000,000)。

他的C(2<=C<=N)頭牛不滿於隔間的位置分佈,它們為牛棚裡其他的牛的存在而憤怒。為了防止牛之間的互相打鬥,Farmer John想把這些牛安置在指定的隔間,所有牛中相鄰兩頭的最近距離越大越好。那麼,這個最大的最近距離是多少呢?

輸入格式:
第1行:兩個用空格隔開的數字N和C。

第2~N+1行:每行一個整數,表示每個隔間的座標。

輸出格式:
輸出只有一行,即相鄰兩頭牛最大的最近距離。

輸入樣例#1:
5 3
1
2
8
4
9
輸出樣例#1:
3

題目分析
這是一到可以很容易看出來的二分題(巨大的查詢範圍可以看出)。
在正常情況下,二分模板都是可以套進去的,但是難點是在對解是否合法的判斷上。

在這一道題目上面,我們可以寫一個子程式來判斷一下,具體的也就是用當前的解,不停的向前面放,如果當前的放不了了,就說明有一個屋子廢了,當然,我們算出最多可以廢幾個屋子,對比一下,即可

到這裡,這一道題就寫完了,
其他的也就是套模板了,這一題是比較適合用while版的二分來寫的

程式碼

#include <bits/stdc++.h>
using namespace std;

int a[1000009],n,k;

bool judge(int x)                //判斷函式
{
	int sum = 0;       //當前一個屋子都沒有廢,
	int now = a[1];   //從第一個開始試
	
	for (int i = 2; i <= n; i++)
		{
			if (now + x > a[i]) sum++;       //判斷當前的是否合法,也就是當前試了這組解後有沒有佔到後面的房子裡,如果有了,這一組就廢了,當前的得放在後面後面
				else        //反之,可以放,繼續向前放
					now = a[i];        //這是下一個的起點
				
			if (sum > n - k) return false;          //判斷是否還有房子可以浪費,沒有了,就說明,這組解,不合法的
		}
	
	return true;         //反之就是合法的
}

int main()
{
	cin>>n>>k;
	for (int i = 1; i <= n; i++) cin>>a[i];                         //輸入
	
	sort(a+1,a+n+1);          //資料必需有序的
	
	int left = 1;        //左界
	int right = a[n] - a[1];          //右界
	
	while (left <= right)
		{
			int mid = (left + right) / 2;        //去中間數
			
			if (judge(mid)) left = mid + 1;           //如果這是一組合法的解,我們就像前試探一下,看一看有沒有更優秀的
				else                         //反之
					right = mid - 1;                      //這一組解不合法,就說明偏大了,向前去找
		}
	
	if (judge(right)) cout<<right;         //判斷更優秀的解
		else
			cout<<left;
			
	return 0;      //完美的結束程式
}
																					** 菜雞c_uizrp_dzjopkl原創**