三分搜索

学完二分查找之后, 再学三分搜索之后确实好很多,而且概念也比较容易理解,但是在实际的问题中用起来还是十分不顺手。费了好半天的劲才把hdu的代码敲下来。

三分的主要思想:


如上图所示,类似二分的定义,mid =left + right/ 2midmid = mid + right/ 2,如果mid靠近极值点,则right = midmid,否则left = mid

模板如下:

double Calc(Type a)
{
     /* 根据题目的意思计算 */
}
 
void Solve()
{
     double left, right;
     double mid, midmid;
     double mid_value, midmid_value;
     left = MIN; right = MAX;
     while (left + EPS < right)
     {
            mid = (left + right) / 2;
            midmid = (mid + right) / 2;
     三分搜索法的模板如下:
double Calc(Type a)
{
     /* 根据题目的意思计算 */
}
 
void Solve()
{
     double left, right;
     double mid, midmid;
     double mid_value, midmid_value;
     left = MIN; right = MAX;
     while (left + EPS < right)
     {
            mid = (left + right) / 2;
            midmid = (mid + right) / 2;
       mid_value = Calc(mid);
            midmid_value = Calc(midmid);
            // 假设求解最大极值.
            if (mid_ value >= midmid_ value) right = midmid;
            else left = mid;
     }
}

看完之后参照学姐的讲课做了一道三分的题目,hdu3400:http://acm.hdu.edu.cn/showproblem.php?pid=3400

这道题的解题思路思路就是:题目要求我们找到A点到D点的最短时间,所以我们需要在AB线段上找一点p1,CD上面找一点p2,这里我们就可以用三分的思想来找。总时间就是在Ap1上面花的时间+p1p2上面花时间+p2D上面花的时间。

代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define EPS 1e-8
using namespace std;

double p, q, r;

struct point
{
    double x;
    double y;
} A,B,C,D;

double dist(point a, point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

double dist_cd(point p1, double m)
{
    point p2;
    p2.x = C.x + (D.x-C.x)*m;
    p2.y = C.y + (D.y-C.y)*m;
    return (dist(D, p2)/q + dist(p1, p2)/r);

}

double time_cd(point p1)
{
    double mid, midmid, mid_value, midmid_value;
    double left = 0.0, right = 1.0;
    while(left+EPS<right)
    {
        mid = (left+right)/2;
        midmid = (mid+right)/2;
        mid_value = dist_cd(p1, mid);
        midmid_value = dist_cd(p1, midmid);
        if(mid_value<midmid_value) right = midmid;
        else left = mid;
    }
    return dist_cd(p1, left);
}

double dist_ab(double m)
{
    point p1;
    p1.x = A.x+(B.x-A.x)*m;
    p1.y = A.y+(B.y-A.y)*m;
    return (dist(A, p1)/p + time_cd(p1));
}

double time_ab()
{
    double mid, midmid, mid_value, midmid_value;
    double left = 0.0, right = 1.0;
    while(left+EPS < right)
    {
        mid = (left+right)/2;
        midmid = (mid+right)/2;
        mid_value = dist_ab(mid);
        midmid_value = dist_ab(midmid);
        if(mid_value<midmid_value) right = midmid;
        else left = mid;
    }
    return dist_ab(left);
}

int main()
{
    int n;
    scanf("%d", &n);
    while(n--)
    {
        scanf("%llf%llf%llf%llf", &A.x, &A.y, &B.x, &B.y);
        scanf("%llf%llf%llf%llf", &C.x, &C.y, &D.x, &D.y);
        scanf("%llf%llf%llf", &p, &q, &r);
        double mintime = time_ab();
        printf("%.2f\n", mintime);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值