hdu3400 _嵌套三分 三分求极限

给出两条平行的线段AB, CD,然后一个人在线段AB的A点出发,走向D点,其中,
人在线段AB上的速度为P, 在线段CD上的速度为Q,
在其他地方的速度为R,求人从A点到D点的最短时间。

在有规律的数据上优化,三分和二分的思路有点类似,主要用于优化 枚举的样例的次数
主要用于凹型数据或者是凸型数据


此题为嵌套三分枚举,


下面思路感觉比较详细所以就从网上拷贝了下来


思路
如上图所示,红线部分为人走的路径。人所用的时间为 T = X / P + Y / Q + Z / R。
ds

然后我们做一个变形,令人在线段AB上花的时间为:F(X) = X / P ,假设X是一个确定值的前提下,
人走完Z和Y所花的时间为:
G(Y) = Z / R + Y / Q。当X 和Y都确定的情况下,Z也是一个确定值。所以,所求的函数可以写成:
 T(X,Y) = F(X) + G(Y)。因为T是一个关于X和Y的函数,而G只是一个关于Y的函数,
 所以,可以用两层嵌套的三分法解这个方程。首先以X为变量,对T进行三分。
 在求G的值的时候,以Y为变量,对G进行三分,求出G在对应的X下的最小值。这样就能求出T的最小值了。

两个函数叠加,所得的T(X,Y)函数应该也是一个先递减后递增的函数。故可用三分法解之。


///切记输入的格式 要定义double否则三分的时候 就会将小数部分消掉,
///因为double问题调试了好久
#include<bits/stdc++.h>
#define eps 1E-10
using namespace std;
struct node
{
    double x,y;
} p1,p2,p3,p4;
int p,q,r;
double dist(node a,node b,int speed)
{
    return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y))/speed;///(1.0*speed);
}

double solve(node Q)
{
    node low=p3,high=p4;
    node mid,midmid;
    double sum1=-1,sum2=0;

  <span style="color:#ff0000;">///如果枚举点的坐标的话,会出现线段成点的情况所以此处枚举了差值的绝对值</span>

    while(fabs(sum2-sum1)>eps)    ///绝对值的比较,因为他不是单调的。
    {

        mid.x=(low.x+high.x)/2;
        mid.y=(low.y+high.y)/2;
        midmid.x=(high.x+mid.x)/2;
        midmid.y=(high.y+mid.y)/2;

        sum1=dist(Q,mid,r)+dist(mid,p4,q);
//        cout<<dist(Q,mid,r)<<endl;
//        cout<<dist(mid,p4,q)<<endl;
        sum2=dist(Q,midmid,r)+dist(p4,midmid,q);
//        cout<<mid.x<<" "<<mid.y<<endl;
//        cout<<midmid.x<<" "<<midmid.y<<endl;
//        cout<<sum1<<" "<<sum2<<endl;

        if(sum1<sum2)
            high=midmid;
        else
            low=mid;
    }
    return dist(Q,mid,r)+dist(mid,p4,q);
}
int main()
{
    int T;
    scanf("%d",&T);
    {
        while(T--)
        {
            scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y);
            scanf("%lf%lf%lf%lf",&p3.x,&p3.y,&p4.x,&p4.y);
            scanf("%d%d%d",&p,&q,&r);

            node low=p1,high=p2,mid,midmid;
            double sum1=-1.0,sum2=0;


            while(fabs(sum2-sum1)>eps)
            {

                mid.x=(low.x+high.x)/2;
                mid.y=(low.y+high.y)/2;
                midmid.x=(high.x+mid.x)/2;
                midmid.y=(high.y+mid.y)/2;

                sum1=dist(p1,mid,p)+solve(mid);
                sum2=dist(p1,midmid,p)+solve(midmid);

                if(sum1<sum2)
                    high=midmid;
                else
                    low=mid;

            }
            //cout<<sum1;
            printf("%.2lf\n",sum1);
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值