刷题记 - XXVI (二分查找)

Posted HouZAJ的堆栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了刷题记 - XXVI (二分查找)相关的知识,希望对你有一定的参考价值。

(QQ音乐没有对应曲目)



前言

首先很抱歉因为考完高数还有一堆事儿,再加上我现在正在啃的东西比较难,所以拿之前做过的一个系统性的东西来凑 T^T
"二分查找是一种思想",这是冬训时师兄的话。个人觉得作为ACMer更重要的是,学了算法和数据结构,能够运用,比如最近张哥发的文章中,有网友提出用二分查找找出窃取照片的人,在个人看来这就是运用啦~哪天个人也能这么聪明就好了 QAQ

Solve It - UVA - 10341


题意
给定p、q、r、s、t,求解给定方程的根
思路
首先要判断单调性,对方程求导,得 -pe^(-x) + qcosx - rsinx + s(secx)^2 + 2xt,把已知条件代入,可得这条式子是恒小于或等于0的,故原方程单调递减,再二分求解即可

 
   
   
 
  1.    #include <iostream>

  2.    #include <cstdio>

  3.    #include <cmath>

  4.    using namespace std;

  5.    const double eps = 1e-7;

  6.    double p, q, r, s, t, u;

  7.    double fun(double x) { return p*exp(-x) + q*sin(x) + r*cos(x) + s*tan(x) + t*x*x + u; }

  8.    int main(){

  9.        while(~scanf("%lf%lf%lf%lf%lf%lf", &p, &q, &r, &s, &t, &u)){

  10.            double l = 0, r = 1;

  11.            while(fun(l) * fun(r) <= 0 && fabs(fun(l)) > eps){

  12.                double mid = (l + r)/2;

  13.                if(fun(mid) > 0){

  14.                    l = mid;

  15.                }else{

  16.                    r = mid;

  17.                }

  18.            }

  19.            if(fabs(fun(l)) < eps){

  20.                printf("%.4f ", l);

  21.            }else{

  22.                printf("No solution ");

  23.            }

  24.        }

  25.    }


Pie - POJ 3122

刷题记 - XXVI (二分查找)题意
有很多个半径为R1,R2,……,Rn的批萨,现在要分同样大小的批萨(可以不同形状)给M个人,问最大大小能是多少
思路
稍微有点隐晦的二分
对所求的最大大小进行二分,分的人数 >= M 就缩左边界,否则缩右边界

 
   
   
 
  1.    #include <iostream>

  2.    #include <cstdio>

  3.    #include <cmath>

  4.    using namespace std;

  5.    const double eps = 1e-7;

  6.    const double PI = acos(-1);

  7.    const int N = 1e4 + 15;

  8.    double rr[N];

  9.    int main(){

  10.        int t;

  11.        scanf("%d", &t);

  12.        while(t--){

  13.            int n, m;

  14.            scanf("%d%d", &n, &m);

  15.            m++;

  16.            for(int i = 0; i < n; i++){

  17.                scanf("%lf", &rr[i]);

  18.            }

  19.            double l = PI/10005.0, r = 10000.0*10000.0*PI;

  20.            while(r - l > eps){

  21.                int sum = 0;

  22.                double mid = (l + r)/2.0;

  23.                for(int i = 0; i < n; i++){

  24.                    sum += (int)(rr[i] * rr[i] * PI/mid);

  25.                }

  26.                if(sum >= m){

  27.                    l = mid;

  28.                }else{

  29.                    r = mid;

  30.                }

  31.            }

  32.            printf("%.4f ", l);

  33.        }

  34.    }


Trick or Treat - ZOJ 3386

题意
给定N个不同的点,求在x轴上的一点使得所有点到它的距离中的最大值最小
思路
函数叠加,但仍然先递减后递增,故用三分查找的方法找出最小值

 
   
   
 
  1.    #include <iostream>

  2.    #include <cstdio>

  3.    #include <cmath>

  4.    #include <climits>

  5.    using namespace std;

  6.    const double eps = 1e-5;

  7.    const int N = 50005;

  8.    double coordinate[N][2] = {0};

  9.    double calc(double x1, double y1, double x2, double y2) { return (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2); }

  10.    double f(double x, int n){

  11.        double ans = calc(coordinate[0][0], coordinate[0][1], x, 0.0);

  12.        for(int i = 1; i < n; i++){

  13.            ans = max(ans, calc(coordinate[i][0], coordinate[i][1], x, 0.0));

  14.        }

  15.        return ans;

  16.    }

  17.    int main(){

  18.        int n;

  19.        while((~scanf("%d", &n)) && n){

  20.            for(int i = 0; i < n; i++){

  21.                scanf("%lf%lf", &coordinate[i][0], &coordinate[i][1]);

  22.            }

  23.            double l = -200000.0;

  24.            double r = 200000.0;

  25.            while(r - l > eps){

  26.                double lm = l + (r - l)/3.0;

  27.                double lr = r - (r - l)/3.0;

  28.                if(f(lm, n) < f(lr, n)){

  29.                    r = lr;

  30.                }else{

  31.                    l = lm;

  32.                }

  33.            }

  34.            printf("%.9f %.9f ", l, sqrt(f(l, n)));

  35.        }

  36.    }


Trick or Treat - ZOJ 3386

题意
给定N个点,对于每个点给出它的x, y, vx, vy,问这些点何时能取得最大距离的最小值
思路
首先写一下任意两点的距离公式 d^2 = [(xi + t*vxi) - (xj + t*vxj)]^2 + [(yi + t*vyi) - (yj + t*vyj)]^2,该公式可化简,得到二次函数表达式,先递减再递增
既然是二次函数表达式,那么直接叠加,仍然会先递减,后递增,因此用三分查找的方法找出最小值

 
   
   
 
  1.    #include<iostream>

  2.    #include<string>

  3.    #include<algorithm>

  4.    #include <cstdio>

  5.    #include <cmath>

  6.    using namespace std;

  7.    const int N = 300 + 15;

  8.    const double eps = 1e-5;

  9.    double x[N], y[N], vx[N], vy[N];

  10.    double a[N*N], b[N*N], c[N*N];

  11.    inline double twice(double x) {return x*x;}

  12.    double getMax(double t, int n){

  13.        double ans = 0;

  14.        for(int i = 0; i < n; i++){

  15.            for(int j = i + 1; j < n; j++){

  16.                ans = max(ans, sqrt(twice(x[i] + vx[i]*t - x[j] - vx[j]*t) + twice(y[i] + vy[i]*t - y[j] - vy[j]*t)));

  17.            }

  18.        }

  19.        return ans;

  20.    }

  21.    int main(){

  22.        int t;

  23.        int caseno = 1;

  24.        scanf("%d", &t);

  25.        while(t--){

  26.            int n;

  27.            scanf("%d", &n);

  28.            for(int i = 0; i < n; i++){

  29.                scanf("%lf%lf%lf%lf", &x[i], &y[i], &vx[i], &vy[i]);

  30.            }

  31.            double ans = 0;

  32.            double l = 0, r = 1e6;

  33.            while(r - l > eps){

  34.                double lm = (r - l)/3 + l;

  35.                double rm = r - (r - l)/3;

  36.                double lval = getMax(lm, n);

  37.                double rval = getMax(rm, n);

  38.                if(lval < rval){

  39.                    ans = lval;

  40.                    r = rm;

  41.                }else{

  42.                    ans = rval;

  43.                    l = lm;

  44.                }

  45.            }

  46.            printf("Case #%d: %.2f %.2f ", caseno++, l, ans);

  47.        }

  48.    }


以上是关于刷题记 - XXVI (二分查找)的主要内容,如果未能解决你的问题,请参考以下文章

吃透二分查找—— LeetCode 第 333435 题记

lintcode 刷题:457 经典二分查找问题

二分查找 · first position of target

LeetCode面试刷题技巧-二分查找算法代码思路解析

LeetCodeLCP 12. 小张刷题计划(二分查找)

二分查找刷题