利用二分的思想求最值有关问题
利用二分的思想求最值问题
在求最值问题里,我们最常见的方法是动态规划,回朔法。然而二分思想也是能够解决某一类最值问题,而且这一类最值问题会用明显的特征。
先来看题目hiho第38周题目:http://hihocoder.com/contest/hiho38/problem/1
将该题目稍微简化模型,意思就是求点到点的最长路径边的最小值。该题目是不能用动态规划的,因为并不存在动态转移方程。因此只能用回朔法。但是这类题目有明显的特征就是:我们一个确定2个值,left_value,right_value,left_value一定不满足题目要求,而right_value则一定满足题目要求。故我们要找的最小值一定是在区间[left_value,right_value]内,一点有序区间去寻找某个值就可以用二分的思想。该替思路如下:
其中打红色方框的就是该类型题目的共性,不同的则是需要根据题意,编写不同的f(x)函数。
该题源代码(已accept)如下:
#include<cstdio> #include<cstring> #include<queue> #include<utility> #include<vector> #include<algorithm> #define PMAXN 10010 #define GMAXN 200010 using namespace std; struct edge { int id; int next; int value; // edge(int value,int _id=0,int _next=-1):id(_id),next(_next){} }; int pnode[PMAXN]; //用来存放点 edge lines[GMAXN]; //用来存放边 bool vis[PMAXN]; int lines_index=0; //边数组的索引下标 int n,m,k,t; int key[GMAXN]; //用来存放边权 int key_index=0; void add(int l,int r,int value) { lines[lines_index].id=l; lines[lines_index].next=pnode[r]; lines[lines_index].value=value; pnode[r]=lines_index++; lines[lines_index].id=r; lines[lines_index].next=pnode[l]; lines[lines_index].value=value; pnode[l]=lines_index++; } //不能使用深搜,会超时,因为深搜会使用递归,数据太大真不好用 bool f(int x) { memset(vis,false,sizeof(vis)); queue<pair<int,int> > q; q.push(make_pair(1,0)); vis[1]=true; while(!q.empty()) { int node=q.front().first; int num=q.front().second; if(num>=k) return false; q.pop(); for(int i=pnode[node];i!=-1;i=lines[i].next) { if(lines[i].value>x||vis[lines[i].id]) continue; if(lines[i].id==t) return true; q.push(make_pair(lines[i].id,num+1)); vis[lines[i].id]=true;; } } return false; } int BinaryAnswer(int left,int right) { if(left==right-1) return right; int mid=(left+right)/2; if(f(key[mid])) return BinaryAnswer(left,mid); else return BinaryAnswer(mid,right); } int main() { freopen("a.txt","r",stdin); scanf("%d%d%d%d",&n,&m,&k,&t); for(int i=0;i<=n;i++) pnode[i]=-1; for(int i=0;i<m;i++) { int l,r,value; scanf("%d%d%d",&l,&r,&value); key[key_index++]=value; add(l,r,value); } sort(key,key+key_index); int *p=unique(key,key+key_index); key_index=p-key; if(f(key[0])) printf("%d",key[0]); else printf("%d",key[BinaryAnswer(0,key_index-1)]); return 0; }
来看一到hiho上微软面试题,同样使用的是二分搜索。 http://hihocoder.com/problemset/problem/1095
源代码(已accept)如下:
#include<cstdio> #define maxn 100010 int n,k; int d[maxn]; //每一次的随机数 int hi,ho,ho_cup; //true表示小ho赢 bool f(int t) { hi=0,ho=0; int ho_cup=t; for(int i=0;i<n;i++) { if(ho_cup<=d[i]) { hi++; ho_cup=0; } else { ho++; ho_cup-=d[i]; } ho_cup+=t; } return ho>hi; } int BinarySearch(int l,int r) { if(l==r-1) return r; int mid=(l+r)/2; if(f(mid)) return BinarySearch(l,mid); else return BinarySearch(mid,r); } int main() { freopen("a.txt","r",stdin); scanf("%d%d",&n,&k); for(int i=0;i<n;i++) scanf("%d",d+i); printf("%d",BinarySearch(0,k+1)); return 0; }