1. 程式人生 > >洛谷 P1824 進擊的奶牛 【二分答案】(求最大的最小值)

洛谷 P1824 進擊的奶牛 【二分答案】(求最大的最小值)

函數 邊界 TP 大於 輸入格式 要求 初始 位置 style

題目鏈接:https://www.luogu.org/problemnew/show/P1824

題目描述

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

解題思路:
像這種求最大最小值,最小最大值得問題都是典型的二分答案題,二分答案的主要難點在於juge()函數,此題下面給出了兩個不同思路的juge函數。

要註意的是如何根據所枚舉的答案來將隔間分隔,因為求的是最大的最近距離,這個距離要是每一次分隔距離中最短的。接下來分析,假設隔間的坐標沒有規定在哪的話,那麽什麽時候最近距離最大呢?毫無疑問,是當所有的距離
相同的時候,最近距離最大。但是此題每個隔間的坐標有規定,使得不一定能使每一段的距離都能夠相等,所以,此時求最近距離的最優思路就是:

每一段區間距離都應該大於或等於m(但要盡可能的接近最近距離),這樣才能使最近距離最大
所以一旦所枚舉的隔間距離恰好大於最近距離的時候,就在該隔間放牛,毫無疑問,這樣得到的最近距離才會盡可能的大

第一種juge()函數

bool juge(int m)//判斷距離m是否可以 
{
    int s = 0, last = 1;//記錄上一個 
    for (int i = 2; i <= n; i++)//依次枚舉每個牛欄 
    {
        if (a[i] - a[last]<m)s++;//若此距離不滿足當前答案,那麽需要的牛欄數+1,即把當前牛放到下一個牛欄 
        else
last = i;//否則就更新上一次的牛欄位置 ,即上一頭牛放的位置 if (s>n - c) return false;//若需要牛欄數大於最大牛欄數,此答案不可行 } return true; }

第二種juge()函數
bool juge(int m)              
{
    int ans = 1, last = 1;           //因為第一個牛一定要占據第一個隔間(這樣能使本題的答案最優),所以ans初始化為1
    for (int i = 2; i <=n; i++)
    {
        if (a[i] - a[last] >= m)
        {
            ans++;           //如果比最近距離要大的話,那麽該隔間就放牛   
            last = i;                                               
        }
    }
    if (ans >= c)return true;          
    return false;
}

本題代碼

#include <bits/stdc++.h>
using namespace std;
int a[100010];
int l, r;
int n,c;

/*bool juge(int m)//判斷距離m是否可以 
{
    int s = 0, last = 1;//記錄上一個 
    for (int i = 2; i <= n; i++)//依次枚舉每個牛欄 
    {
        if (a[i] - a[last]<m)s++;//若此距離不滿足當前答案,那麽需要的牛欄數+1,即把當前牛放到下一個牛欄 
        else last = i;//否則就更新上一次的牛欄位置 ,即上一頭牛放的位置 
        if (s>n - c) return false;//若需要牛欄數大於最大牛欄數,此答案不可行 
    }
    return true;
}*/

bool juge(int m)              
{
    int ans = 1, last = 1;           //因為第一個牛一定要占據第一個隔間(這樣能使本題的答案最優),所以ans初始化為1
    for (int i = 2; i <=n; i++)
    {
        if (a[i] - a[last] >= m)
        {
            ans++;           //如果比最近距離要大的話,那麽該隔間就放牛   
            last = i;                                               
        }
    }
    if (ans >= c)return true;          //如果所選取的隔間數量>=c,則說明枚舉的最近距離成立,但是不夠大,所以return true,繼續枚舉更大的距離
    return false;
}

int main()
{
    cin >> n >> c;
    for (int i = 1; i <=n; i++)cin >> a[i];
    l = 1; r = a[n] - a[1];           //右邊界為n個隔間的總長度,最近距離一定小於等於這個數值
    sort(a + 1, a + 1 + n);
    while (l <= r)
    {
        int mid = (l + r)/2;
        if (juge(mid))l = mid+1;       //如果當前枚舉的最近距離符合,那麽就讓l=mid,看更大的距離是否也符合(因為要求最大的最近距離)
        else
            r = mid-1;
    }
    cout << r<< endl;    //由於最後l<=r的時候還會運行一次,會讓l-1(如果答案正確的話),所以應該輸出的是r
    return 0;
}


2018-05-20

洛谷 P1824 進擊的奶牛 【二分答案】(求最大的最小值)