有一類常見問題叫作最小值最大化或者最大值最小化。這類問題通常是用二分搜索來解決。html
首先二分搜索解決的問題必須具有單調性這個性質,這是使用二分搜索的必要條件,咱們分析兩個問題。node
1.最小值最大化:咱們假設x爲最大的最小值,那麼x-1是知足條件的,但他並不知足最大,x+1是不知足條件的,假設咱們左邊界是L,右邊界是R,咱們二分一個答案ans,ans爲最後一個知足條件的數,咱們是否是能夠類比二分搜索(一)中的last_less_equal()或者last_less()這個問題和這二者是差很少的。能夠先閱讀個人另外一篇博文:二分搜索(一)——各類二分c++
2.最大值最小化:咱們假設x爲最小的最大值,那麼x-1是不知足條件的,x+1是知足條件的,但他不知足最小,假設咱們左邊界是L,右邊界是R,咱們二分一個答案ans,ans爲第一個知足條件的數,咱們是否是能夠類比二分搜索(一)中的lower_bound()或者upper_bound()這個問題和這二者是差很少的。less
因此綜上所述並根據我在二分搜索(一)——各類二分中的描述:最小值最大化的二分區間是右閉左開(L,R],每次二分的中心爲M=(L+R+1)/2;最大值最小化的二分區間是左閉右開,[L,R),每次二分的中心爲M=(L+R)/2。ide
題目意思:你有b塊錢,想要組裝一臺電腦。給出n個配件格子的種類,品質因子和價格,要求每種類型的配件各買一個,總價格不超過b,且品質最差的配件的品質因子儘可能大。spa
思路:這很明顯是一個最小值最大化的問題,這道題還用到map對物品按名稱進行分類,注意多組輸入,要對上一組的數據進行清空,咱們能夠看出二分邊界L=-1,R=maxq(全部商品中品質因子的最大值。),也就是右閉左開區間(L,R],咱們搜索最後一個知足條件的ans值,具體看代碼吧。.net
代碼:code
#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; }
題目意思:農民約翰有用C只牛,而後他有N個隔間,每一個隔間都有本身的座標位置(一維的)pos,如何安排把牛安排進隔間才能使,全部牛之間距離的最小值最大,咱們不須要求這個分配方案,咱們只須要求這個最小距離的最大值,很裸的最小值最大化。htm
思路:直接看代碼吧blog
代碼:
#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; }
題目意思:共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; }