南陽nyoj586瘋牛 和nyoj619詳解總結

這裏先看nyoj619青蛙過橋,這樣便於理解這兩道題的共同點:最大值中的最小值

題意:有一條河長L,中間有 n 塊石頭,青蛙最多可以跳 m 次,問題是:要保證青蛙能跳過去,那麼它至少能一下跳多遠,才能在m次範圍內跳過去;

最大值中的最小值:這裏要保證m次能跳過去,那麼在這個過程中就會有很多種方法能在m次之內跳過去,那麼,每一個方法中,我們就會有一個最大的跳躍距離!

比如:L=20,n=1;m=2;石頭的位置是5

那麼方法有:1.一次就跳過去,2.藉助中間的石頭,兩次跳過去;那麼在方法一中的最大的距離就是20,在第二種方法中,最大的距離就是15,那麼方法二中的最大值15就是所有最大值中的最小的一個,也就是保證青蛙跳過去的至少能跳的距離


解決:這裏要用到二分加貪心

二分時候,區間(l,r),l是石頭兩兩之間最大的距離,r是L河寬,mid=(l+r)/2作爲每次應該跳躍的距離,然後二分貪心;

貪心過程中,對於二分中的每一個mid的值,我們貪心求出以這個距離跳躍,能多少次跳過河!

上馬,代碼中註釋:


#include <iostream>
#include <algorithm>
using namespace std;

#define MAX 500005

int L,n,m;
int stone[MAX];

int jump(int x)
{
    int cnt = 1;
    int sum = 0;//青蛙每次的起跳點,初始爲0
    for(int i = 0; i <= n; i ++)
    {
        if(stone[i] - sum == x )//如果這個石頭到sum這點的距離剛好是x,那麼剛好能跳過,sum更新爲這個石頭座標
        {
            cnt ++;
            sum = stone[i];
        }
        else if(stone[i] - sum > x)//青蛙不能從sum跳到stone,那麼,sum就更新爲前面那個石頭的座標
        {
            cnt ++;
            sum = stone[i-1];
        }
    }
    return cnt;
}

int main()
{
    while(cin>>L>>n>>m)
    {
        for(int i = 0; i < n; i ++) cin>>stone[i];
        sort(stone,stone+n);
        stone[n] = L; //把河的寬度加入

        int l,r;
        r = L;
        l = 0;
        for(int i = 1; i <= n; i ++)//找二分區間的左值
        {
            if(stone[i] - stone[i-1] > l) l = stone[i]-stone[i-1];
        }

        int mid;
        while(l <= r)
        {
            mid = (l+r)/2;
            if(jump(mid) <= m) r = mid-1;
            else l = mid+1;
        }
        cout <<l<<endl;
    }
    return 0;
}

nyoj586瘋牛

這裏和上面只有一點點區別:

第一:二分區間的左右值(0,cow[n-1]-cow[0]);(排好序之後的);

第二:青蛙那題是跳的次數,而這裏是安排的牛數,就像線段上的點的關係一樣,一個線段,兩個端點,類似於青蛙要跳一次,但是可以安排兩頭牛在兩個端點上,那麼這裏二分的時候,判斷就應該是 <= c-1;  而不是青蛙那裏的 <=m

第三就是貪心過程中,不要區分 == x 和 > x的情況

具體看代碼:

#include <iostream>
#include <algorithm>
using namespace std;

#define MAX 100005

int n,c;
int cow[MAX];

int din(int x)
{
    int cnt = 1;
    int sum = cow[0];
    for(int i = 1; i < n; i ++)
    {
        if(cow[i] - sum >= x) //不要區分,滿足就把牛放在這點,sum更新爲此點座標,應爲青蛙那不能跳過來,就是前面一點
        {
            cnt ++;
            sum = cow[i];
        }
    }
    return cnt;
}

int main()
{
    while(cin>>n>>c)
    {
        for(int i = 0; i < n; i ++) cin >> cow[i];
        sort(cow,cow+n);

        int l = 0;
        int r = cow[n-1]-cow[0];

        int mid;
        while(l <= r)
        {
            mid = (l+r)/2;
            if(din(mid) <= c-1) r = mid-1;
            else l = mid+1;
        }
        cout<<l-1<<endl;
    }
    return 0;
}
個人愚昧觀點,歡迎討論與指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章