0.題目
題目描述
一年一度的「跳石頭」比賽又要開始了!
這項比賽將在一條筆直的河道中進行,河道中分佈著一些巨大岩石。組委會已經選擇好了兩塊岩石作為比賽起點和終點。在起點和終點之間,有 N 塊岩石(不含起點和終點的岩石)。在比賽過程中,選手們將從起點出發,每一步跳向相鄰的岩石,直至到達終點。
為了提高比賽難度,組委會計劃移走一些岩石,使得選手們在比賽過程中的最短跳躍距離儘可能長。由於預算限制,組委會至多從起點和終點之間移走M 塊岩石(不能移走起點和終點的岩石)。
輸入描述
輸入檔案第一行包含三個整數 L,N,M,分別表示起點到終點的距離,起點和終點之間的岩石數,以及組委會至多移走的岩石數。
接下來 N 行,每行一個整數,第 i 行的整數 Di(0 < Di < L)表示第 i 塊岩石與起點的距離。這些岩石按與起點距離從小到大的順序給出,且不會有兩個岩石出現在同一個位置。
其中,0≤M≤N≤5×104 ,1≤L≤109 。
輸出描述
輸出只包含一個整數,即最短跳躍距離的最大值。
樣例輸入
25 5 2
2
11
14
17
21
樣例輸出
4
1.題解
1.0 暴力列舉(超時)
思路
列舉\(C_n^m\)種情況,分別求得個情況的最小d,挑出其中的最大值
1.1 二分法
思路
同樣都是列舉,這裡我不列舉你的情況了,我列舉所有可能的d值,可能的d值正好排成一個有序單調遞增序列(適合二分查詢)
這裡直接套上二分模板, 但是注意這裡的判斷條件由之前的 a[mid] >= n / <= n
改變為根據我們這題實際需求滿足能透過移動m塊石頭使每個間距均大於等於d的情況(check函式)
這裡可以透過貪心思想轉換為移動不多於m塊石頭使每個間距均大於等於d的情況, 因為我如果使用移動少於m塊石頭都能滿足條件,移動更多石頭只會使間距更大,依舊滿足條件!
程式碼
#include<bits/stdc++.h>
using namespace std;
const int Maxn = 1e5;
int stone[Maxn];
int len, n, m;
// 檢測能否透過移動 m塊石頭達成最小距離>d
bool check(int d) {
int pos = 0; // 當前位置
int num = 0; // 總共移走的石頭數目
for(int i = 1; i <= n+1; i++){
// 這裡可以這樣理解, (由於起點不可動)前面都是如果不滿足,就移走stone[i]這塊石頭
// 否則保留這開始石頭,更新我目前的位置到stone[i]
// 但是最後如果stone[n+1] - pos < d?怎麼辦,終點石頭不能移,好辦,移走其前面一塊(pos)石頭即可,特殊思考一下,但不需要特殊處理
if(stone[i] - pos < d){
num++;
if(num > m) return false;
} else{
pos = stone[i];
}
}
return true;
}
int main() {
cin >> len >> n >> m;
stone[n+1] = len;
for(int i = 1; i <= n; i++) {
cin >> stone[i];
}
int l = 0, r = len;
while(l < r) {
int d = (r - l + 1) / 2 + l;
if(check(d)) {
l = d;
} else {
r = d - 1;
}
}
cout << l;
return 0;
}