1. 程式人生 > >【51NOD-1243-排船問題】 二分

【51NOD-1243-排船問題】 二分

51NOD1243排船問題
題意
N

N
2 X M
一個碼頭中有N艘船和N個木樁,船的長度為2*X,碼頭的寬度為M
N N個木樁的位置(相對碼頭左岸的位置)會在資料中給出
船和船之間不能重疊,即每艘船的船頭不能超過上一艘船的船尾,當然也不能超出碼頭的兩岸
1 1 船和木樁之間用繩子連線,並且1個木樁只能栓1條船,繩子的一頭拴在木樁上,另一頭拴在船的中間
而船中間到木樁的距離,就是所需的繩子的長度。由你根據給出的條件,排列船的位置
使 1 使得所用到的最長的繩子最短。輸出這個最短的長度,如果碼頭排不下所有船則輸出-1。
做法
我們發現答案肯定是具有二分性質的,所以我們只要二分答案驗證即可
驗證答案是否可行的時候,儘量把船靠的最近,看最後一個船是否超過右邊界即可
程式碼

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl
const int maxn = 5e4+10;
int a[maxn];
int n,x,m;
bool check(int mid)
{
    int head=0,tail=0;
    for(int i=1;i<=n;i++)
    {
        head=tail;
        if(head+x-mid<=a[i])
        {
            if(head+x+mid<=a[i])
            {
                head=a[i]-x-mid;
                tail=head+2*x;
            }
            else
            {
                tail+=2*x;
            }
        }
        else
        {
            return 0;
        }
    }
    return tail<=m;
}
int main()
{
    scanf("%d%d%d",&n,&x,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int l=0,r=m-1;
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(check(mid)) r=mid-1;
        else l=mid+1;
    }
    if(l==m||2*n*x>m) printf("-1\n");
    else printf("%d\n",l);
    return 0;
}