leetcode 5489. 兩球之間的磁力& lg P1824 進擊的奶牛(二分)
阿新 • • 發佈:2020-08-16
題目連結:
leetcode 5489兩球之間的磁力:https://leetcode-cn.com/problems/magnetic-force-between-two-balls/
lg P1824 進擊的奶牛:https://www.luogu.com.cn/problem/P1824
這兩題都是用二分法求最小值中的最大值,說來慚愧,今天做lc5489這道題時沒有思路,閒著無聊百度了一下"求最小值中的最大值",就找到了lg這道題,然後就暢通無阻做出來了...
說到底還是題目做的少,對題型不熟悉,這兩題都是用二分列舉最大值,然後對於每一個最大值去check一下,check是用到一個小貪心思想,然後就沒了...思想比較簡單,可以看程式碼理解。
//leetcode 5489. 兩球之間的磁力 class Solution { public: bool check(int dis,vector<int>& pos,int m){ //貪心的放 int last = pos[0];m--; for (int i = 1; i < pos.size(); i++){ if (pos[i]-last >= dis){ m--; last = pos[i]; } } if (m > 0) return false; //放不完就不符合條件 return true;//反之就ok } int maxDistance(vector<int>& pos, int m) { sort(pos.begin(),pos.end()); int left = 0,right = pos.back()-pos[0]; int ans; while(left <= right){ //二分答案 int mid = (left+right)/2; if (check(mid,pos,m)){ ans = mid; left = mid+1; // cout<<right<<endl; } else right = mid-1; } return ans; } }; //lg P1824 進擊的奶牛 #include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int maxn = 1e5+50; int pos[maxn],n,c; bool check(int x){ int last = pos[1],now = c; now--; for (int i = 2; i <= n; i++){ if (pos[i] - last >= x){ last = pos[i]; now--; } } if (now > 0) return false; return true; } int main() { scanf("%d%d",&n,&c); for (int i = 1; i <= n; i++){ scanf("%d",&pos[i]); } sort(pos+1,pos+n+1); int left = 0,right = pos[n]-pos[1],ans = 0; while(left <= right){ int mid = (left+right)/2; if (check(mid)){ ans = mid; left = mid+1; //cout<<"ans:"<<ans<<endl; }else right = mid-1; } printf("%d",ans); return 0; }
最後在寫一下常用的二分模板吧,當然具體怎麼用看個人喜好和題目要求
//經過跌跌撞撞得探索,二分法的寫法有兩種 //方法1: while(left < right){ int mid = (left+right)/2; if (check(mid)) right = mid; else left = mid+1; } return left; //用這種方法寫最終while迴圈結束的條件一定是left == right,這種寫法就是我們讓right一直佔據著答案,然後讓left不斷逼近right,最終left == right 得到right所佔據的答案 //方法2: int ans; while (left <= right){ int mid = (left + right)/2; if (check(mid)){ ans = mid; right = mid-1; }else left = mid+1; } return ans; //這種寫法是如果我們有符合條件的答案,我們用ans來儲存,每次更新都使left和right所指的範圍是一個新的範圍 /*具體用哪一種方法要看具體題目,如果題目在二分時是:if (check(mid)) right = mid;else left = mid+1;這樣的,個人常用方法一,如果二分條件是 if (check(mid)) left = mid; else right = mid+1;這時就要用方法二了,因為如果這樣還用方法一的話會陷入死迴圈(如只有兩個數) 具體怎麼用看個人習慣*/