c++二分答案 之 跳石頭


題目:


 

題目描述 Description

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

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

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

 

輸入描述 Input Description

輸入文件名為 stone.in。 

輸入文件第一行包含三個整數L,N,M,分別表示起點到終點的距離,起點和終點之間的岩石數,以及組委會至多移走的岩石數。 

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

 

輸出描述 Output Description

輸出文件名為stone.out。 

輸出文件只包含一個整數,即最短跳躍距離的最大值。

 

樣例輸入 Sample Input

25 5 2

11 

14 

17

21

樣例輸出 Sample Output

4

數據范圍及提示 Data Size & Hint

對於20%的數據,0≤M≤N≤10。 對於50%的數據,0≤M≤N≤100。 

對於50%的數據,0≤M≤N≤100。

對於100%的數據,0≤M≤N≤50,000,1≤L≤1,000,000,000。


 

咋說呢,這題一開始看覺得:哎呀,肯定動規。然后看數據:10^9,然后瞬間懵逼了。於是上網查:要用個東西叫做……二分答案。

先上代碼再解釋:


 

#include <iostream>
using namespace std;
int l,n,m,a[50005],ans;
bool check(int dis)
{
    int count=0,last=0;
    for(int i=1;i<=n;i++)
        if(a[i]-last<dis)count++;
            else last=a[i];
    if(count>m)return 0;return 1;
}
int main()
{
    ios::sync_with_stdio(0);
    cin>>l>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    a[n+1]=l;
    int fl=0,fr=l;
    while(fl<=fr)
    {
        int mid=(fl+fr)/2;
        if(check(mid))fl=mid+1,ans=mid;
            else fr=mid-1;
    }
    cout<<ans;
    return 0;
}

嗯,啥意思呢?輸入我就不講了,然后這個fl,fr是什么呢?

二分查找肯定會吧?【不會的先洗洗睡吧別往下看了】這個fl,fr就是查找答案的范圍的左邊界和右邊界。查找啥呢?都說了是二分答案,你說二分啥?二分距離唄。意思是我們現在要找到一個最大值的距離,這個距離能保證只搬走m或m以內個石頭就能讓任意兩個相鄰的石頭之間的距離≥這個距離。我們就來二分查找滿足這個條件的最大的距離。

先是從0~L之間查找這個距離,取中間值,也就是L/2,然后看L/2這個距離是否滿足上面那個條件,如果滿足那個條件,就把二分查找的左邊界調到中間值(也就是L/2)的右邊一個去,這樣再次查找的范圍就排除了不可能存在最優解的左半邊(因為左半邊所有滿足或者不滿足上面那個條件的所有距離都會小於L/2這個距離,所以不可能存在(不然為啥不選L/2這個值呢?L/2也滿足那個條件啊)),並且在這里還要記住中間值,因為他是目前的最優解。如果中間值(當前是L/2)不滿足那個條件,那L/2的右邊的所有距離也都不可能存在某個距離能滿足那個條件了(要不然L/2也會滿足那個條件的,對吧?),所以就把查找的右邊界調到中間值的左邊一個去。

當我們處理完上一步后,就得到了一個新的查找區間——原區間的左半邊或者右半邊。再在這個查找區間用上面的方法查找,直到區間里沒有數字了,查找結束。輸出答案。


 

附上二分答案模板:

int l,r,mid,ans;
while(l<=r)
{
	mid=(l+r)/2;
	if(check(mid))l=mid+1,ans=mid;
	else r=mid-1;	
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM