洛谷 P1824 進擊的奶牛 【二分答案】(求最大的最小值)
阿新 • • 發佈:2018-05-20
函數 邊界 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,即把當前牛放到下一個牛欄 elselast = 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 進擊的奶牛 【二分答案】(求最大的最小值)