1. 程式人生 > >POJ 2456 Aggressive cows(二分查詢 最大化最小值)

POJ 2456 Aggressive cows(二分查詢 最大化最小值)

題意:給出n個牛棚的位置,選擇其中的m個給牛住,使得牛之間的距離的最小值最大。

首先我們可以知道距離的最小值一定產生於相鄰的牛之間,所以要保證相鄰牛之間的距離大於等於這個最小值d。所以把牛棚的位置從小到大排序,然後在最小的那個位置先放一頭牛,再找下一個牛棚放牛,下一個位置和當前的位置間隔必須大於等於d。如果滿足條件,即可以找到m個牛棚給牛住,那麼再嘗試讓d大一點。為什麼每一次都是大於等於d?就算這一輪沒有出現距離剛好為d的情況,那麼下一次一定可以找到一個距離剛好為d'的情況,其中d'就是這輪中距離的最小值,並且這個d'比d更大。由於mid的時候可能就是最終解,所以區間是左閉右開,要把mid包括進來,最後輸出l。

至於為什麼第一頭牛一定是放在位置最小的地方,可以假設如果放在次小的地方,那麼如果最小值只可能被改得更小,或者不變。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cmath>
#include<algorithm>
#define N 100010
#define INF 0x3f3f3f3f
using namespace std;
int n, c, l, r, mid, st, ed, site[N];
bool ok(int x)
{
    st = 0;
    ed = 0;
    for (int i = 0; i < c-1; i++)
    {
        while (site[ed+1] - site[st] < x && ed+1 < n) ed++;
        if (ed+1 == n) return false; //原本下一個牛應該放在[0,n-1]中,現在要超過n-1,說明已經沒有地方可以放了
        st = ed+1;
        ed = st;
    }
    return true;
}
int main()
{
    scanf("%d%d", &n, &c);
    for (int i = 0; i < n; i++)
        scanf("%d", &site[i]);
    sort(site, site+n);
    site[n] = INF;
    l = 0;
    r = INF;
    while (r - l > 1)
    {
        mid = (l + r) / 2;
        if (ok(mid)) l = mid;
        else r = mid;
    }
    printf("%d\n", l);
}