1. 程式人生 > >洛谷P2678 跳石頭(二分答案)

洛谷P2678 跳石頭(二分答案)

題目背景
一年一度的“跳石頭”比賽又要開始了!

題目描述
這項比賽將在一條筆直的河道中進行,河道中分佈著一些巨大岩石。組委會已經選擇好了兩塊岩石作為比賽起點和終點。在起點和終點之間,有 NN 塊岩石(不含起點和終點的岩石)。在比賽過程中,選手們將從起點出發,每一步跳向相鄰的岩石,直至到達終點。

為了提高比賽難度,組委會計劃移走一些岩石,使得選手們在比賽過程中的最短跳躍距離儘可能長。由於預算限制,組委會至多從起點和終點之間移走 MM 塊岩石(不能移走起點和終點的岩石)。

輸入輸出格式
輸入格式:

第一行包含三個整數 L,N,ML,N,M,分別表示起點到終點的距離,起點和終點之間的岩石數,以及組委會至多移走的岩石數。保證 L \geq 1L≥1 且 N \geq M \geq 0N≥M≥0。

接下來 NN 行,每行一個整數,第 ii 行的整數 D_i( 0 < D_i < L)D
i
​ (0<D
i
​ <L), 表示第 ii 塊岩石與起點的距離。這些岩石按與起點距離從小到大的順序給出,且不會有兩個岩石出現在同一個位置。

輸出格式:
一個整數,即最短跳躍距離的最大值。

輸入輸出樣例
輸入樣例#1
25 5 2
2
11
14
17
21
輸出樣例#1
4
說明
輸入輸出樣例 1 說明:將與起點距離為 22和 1414 的兩個岩石移走後,最短的跳躍距離為 44(從與起點距離 1717 的岩石跳到距離 2121 的岩石,或者從距離 2121 的岩石跳到終點)。

另:對於 20%20%的資料,0 ≤ M ≤ N ≤ 100≤M≤N≤10。

對於50%50%的資料,0 ≤ M ≤ N ≤ 1000≤M≤N≤100。

對於 100%100%的資料,0 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,0000≤M≤N≤50,000,1≤L≤1,000,000,000。

有什麼不懂的地方洛谷搜尋此題 看最高讚的題解 翔哥大佬親筆
或者看看我的一點見解

#include <iostream>
#define maxn 50005
using namespace std; 
int s,n,m;
int a[maxn];
int judge (int x)
{
	int cnt=0; //cnt代表移走石頭的塊數
int now=0; //now代表人現在的位置(注意,起點和終點也算是兩個位置,不止是在石頭上) for(int i=1;i<=n+1;i++) { if(a[i]-a[now]<x) //如果後一塊石頭到前一塊石頭的距離比我們假設的最小值還要小,則移走這塊石頭 cnt++; else now=i; //如果大於等於我們假設的最小值,則跳過去,更新人的位置 } if(cnt>m) //如果搬走的石頭比限制搬走的石頭多,那這個答案是錯的,否則是可行答案(但不一定是最優解,要等最後才能決定最優解) return 0; else return 1; } int main() { int L,R; int ans; cin>>s>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; a[n+1]=s; L=0;R=s; //做二分答案,首先確定答案的範圍,按邏輯來說最小值是兩塊石頭離初始點距離之差的最小值,最大值是從起點到最後一塊石頭的距離,我們直接擴大這個範圍,走極端,最小就是0,最大時初始點到終點的距離(因為二分這個區間是答案所在的區間,只要答案在裡面就可以,可大不可小) while(L<=R) { int mid=(L+R)/2; if(judge(mid)) { ans=mid; L=mid+1; //為什麼答案滿足後繼續往右找?題目要求“使得選手們在比賽過程中的最短跳躍距離儘可能長” } else R=mid-1; } cout<<ans<<endl; return 0; }