关于二分法中取中间值时向下和向上取整的问题(由大白LA3971想到的)
最近在做刘汝佳的大白,有一道题目LA_3971,也是UVA_12124,是用二分法做的。
/************************************************************************* > File Name: 12124.cpp > Author: BobLee > Mail: wustboli@gmail.com > Created Time: Mon 25 Mar 2013 08:36:44 PM CST ************************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<string> using namespace std; const int maxn = 1010; struct co { int price; int qua; }; map<string,int> id; vector<co> com[maxn]; int N,B; int cnt; int ID(string s) { if(!id.count(s)) id[s] = cnt++; return id[s]; } bool fun(int q) { int sum = 0; for(int i=0;i<cnt;i++) { int cheap = B+1; int m = com[i].size(); for(int j=0;j<m;j++) { if(com[i][j].qua>=q) cheap = min(cheap,com[i][j].price); } if(cheap > B) return false; sum+=cheap; if(sum>B) return false; } return true; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int t; scanf("%d",&t); while(t--) { scanf("%d%d",&N,&B); char type[30],name[30]; int price,quaa; int maxq = 0; cnt=0; for(int i=0;i<N;i++) com[i].clear(); for(int i=0;i<N;i++) { scanf("%s%s%d%d",type,name,&price,&quaa); maxq = max(maxq,quaa); com[ID(type)].push_back((co){price,quaa}); } int L=0; int R=maxq; while(L<R) { int M=(L+R+1)/2; //cout<<L<<" "<<R<<" "<<M<<endl; if(fun(M)) { L=M; } else R=M-1; //cout<<L<<" "<<R<<" "<<M<<endl; //getchar(); // if(M==0) // break; } printf("%d\n",L); } return 0; }
可以看到我取中值的时候,用的是向上取整。(实际上是刘汝佳这么写的)
我当时写的是 M=(L+R)/2; 也就是向下取整的意思,但是在不同提交的遇到了一个问题。
我的TLE了。
当时我是百思不得其解,后来仔细思考了之后发现了一个问题。那就是你在这个程序中是求一个合理区间的最大值。
举个例子,假如我们的最后要取的值为5,区间也是[0,5],用向下取整的话
则
LR M
0 5 2
25 3
35 4
45 4
45 4
。。。
发现问题了吧,这个时候就会陷入死循环。
再来一个例子,假如我们是求一个合理区间的最小值,二分的代码
while(L<R) { M=(L+R+1)/2; if(ok(M)) R=M; else L=M+1; }
我们还是用向上取整来做。区间为[0,5],最后的值为0
LR M
0 5 3
03 2
02 1
0 1 1
01 1
。。。
又陷入了死循环,但是我们可以发现如果这时用向下取整就是可行的了。
所以由上面就可以得出,
当我们使用二分法求某个合理区间最值的时候,我们要十分注意两个端点的极端值的情况。
当然还有一种更保险的方法
那就是不用上面的二分的方法
在二分的时候用另外一个变量来记录合理值,然后L=M+1 OR R=M-1
所以这样的话是不回陷入到死循环里面去的
这就是我由这T想到了,好久不写博客了。还是要捡起来啊。