二分搜索(二)——(最小值最大化和最大值最小化)


  有一類常見問題叫做最小值最大化或者最大值最小化。這類問題一般是用二分搜索來解決。

  首先二分搜索解決的問題必須具備單調性這個性質,這是使用二分搜索的必要條件,我們分析兩個問題。

  1.最小值最大化:我們假設x為最大的最小值,那么x-1是滿足條件的,但他並不滿足最大,x+1是不滿足條件的,假設我們左邊界是L,右邊界是R,我們二分一個答案ans,ans為最后一個滿足條件的數,我們是不是可以類比二分搜索(一)中的last_less_equal()或者last_less()這個問題和這兩者是差不多的。可以先閱讀我的另一篇博文:二分搜索(一)——各種二分

  2.最大值最小化:我們假設x為最小的最大值,那么x-1是不滿足條件的,x+1是滿足條件的,但他不滿足最小,假設我們左邊界是L,右邊界是R,我們二分一個答案ans,ans為第一個滿足條件的數,我們是不是可以類比二分搜索(一)中的lower_bound()或者upper_bound()這個問題和這兩者是差不多的。

  所以綜上所述並根據我在二分搜索(一)——各種二分中的描述:最小值最大化的二分區間是右閉左開(L,R],每次二分的中心為M=(L+R+1)/2;最大值最小化的二分區間是左閉右開,[L,R),每次二分的中心為M=(L+R)/2。

  例題1:LA3971-3971——Assemble

   題目意思:你有b塊錢,想要組裝一台電腦。給出n個配件格子的種類,品質因子和價格,要求每種類型的配件各買一個,總價格不超過b,且品質最差的配件的品質因子盡量大。

   思路:這很明顯是一個最小值最大化的問題,這道題還用到map對物品按名稱進行分類,注意多組輸入,要對上一組的數據進行清空,我們可以看出二分邊界L=-1,R=maxq(所有商品中品質因子的最大值。),也就是右閉左開區間(L,R],我們搜索最后一個滿足條件的ans值,具體看代碼吧。

   代碼:

#include<bits/stdc++.h>
using namespace std;
const int N=1000+7;
map<string,int>mp;
struct node{
    int p,q;    
};
vector<node>a[N];
int cnt=0,n,b;
int check(int M){
    long long sum=0;
    for(int i=0;i<cnt;i++){
        int minn=b+10;
        for(int j=0;j<(int)a[i].size();j++){
            if(a[i][j].q>=M){
                minn=min(minn,a[i][j].p);
            }
        }
        sum+=minn;
        if(sum>b) return 0;
    }
    return 1;
}
int main(){
    int T;cin>>T;
    while(T--){
        cin>>n>>b;    
        for(int i=0;i<cnt;i++) a[i].clear();
        cnt=0;
        int L=-1,R=0;
        for(int i=0;i<n;i++){
            string type,name;
            int p,q;
            cin>>type>>name>>p>>q;
            if(mp.count(type)==0){
                mp[type]=cnt++;
            }
            R=max(R,q);
            a[mp[type]].push_back({p,q});
        }
        while(L<R){
            int M=(L+R+1)/2;
            if(check(M)) L=M;
            else R=M-1;
        }
        cout<<R<<endl;
    }
    return 0;
}
View Code

   

  例題2:openjudge-2456——Aggressive cows

    題目意思:農民約翰有用C只牛,然后他有N個隔間,每個隔間都有自己的坐標位置(一維的)pos,如何安排把牛安排進隔間才能使,所有牛之間距離的最小值最大,我們不需要求這個分配方案,我們只需要求這個最小距離的最大值,很裸的最小值最大化。

    思路:直接看代碼吧

    代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+7;
LL n,c,a[N];
int check(int M){
    LL t=c-1,pre=0;
    for(int i=1;i<n;i++){
        if(a[i]-a[pre]>=M){
            t--;
            pre=i;
        }
        if(t==0) break;
    }
    return t==0;    
}
int main(){
    cin>>n>>c;    
    long long minn=0x3f3f3f3f,maxx=-0x3f3f3f3f;
    for(int i=0;i<n;i++){
        cin>>a[i];
        minn=min(a[i],minn); maxx=max(a[i],maxx);
    }
    sort(a,a+n);
    int L=0,R=maxx-minn;    
    while(L<R){
        int M=(L+R+1)/2;
        if(check(M)) L=M;
        else R=M-1;
    }
    cout<<R<<endl;
    return 0;
}
View Code

 

  例題3:openjudge-4135——Monthly Expense

   題目意思:共n個月,給出每個月的開銷.將n個月划分成m個時間段,求m個時間段中開銷最大的時間段的最小開銷值。

   思路:最大值最小化,直接看代碼吧

   代碼:

#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int>a;
int check(int M){
    int ct=0,now=0;
    for(int i=0;i<n;i++){
        if(a[i]>M) return 0;
        if(now+a[i]>M){
            ct++;
            now=0;    
        }    
        now+=a[i];
    }
    return ct<m;
}
int main(){
    cin>>n>>m;
    a.resize(n);
    int R=0,L=0;
    for(int i=0;i<n;i++){
        cin>>a[i];
        R+=a[i];
        L=max(L,a[i]);
    }
    R++;    
    while(L<R){
        int M=(L+R)/2;
        if(check(M)) R=M;
        else L=M+1;
    }
    cout<<L<<endl;
    return 0;
}
View Code

 

 

 

 


免責聲明!

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



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