HDU 3400

一道很适合练习三分的题目三分套三分强不强

题意:给你平面上两条平行线段\(AB\)\(CD\),一个人要从\(A\)走到\(D\),他在线段\(AB\)上的速度为\(P\),在\(CD\)上的速度为\(Q\),在其他地方的速度为\(R\)。求从\(A\)\(D\)的最短时间。

这题目我想在许多初中数学题中经常可以看见。我们只需要在\(AB\)上取一点\(E\),在\(CD\)上取一点\(F\),然后按\(A\to E\ E\to F\ F\to D\)的 顺序即可算出时间。

我们先考虑已知\(E\)的位置,如何确定\(F\)

这个还是很好想的,\(F\)肯定在一个位置时可以保证\(E\to F\ F\to D\)的时间最短。这个证明都不用吧

然后这就是一个凹性函数,我们有发现\(E\)的移动过程中\(A\to E\)是一个正比例函数,然后两条函数一重合——就还是一个凹性函数

然后我们对于\(E\)的位置也可以三分求解。这样我们三分套三分即可解决。

但是这一注意有一个坑点:所给的线段不一定平行于\(x\)轴或\(y\)轴。所以我们要三分比例

这个具体还是看CODE的做法吧

#include<cstdio>
#include<cmath>
using namespace std;
typedef double DB;
const DB EPS=1e-6;
struct point
{
    DB x,y;
}A,B,C,D;
int P,Q,R,T;
inline DB dis(point A,point B)
{
    return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
inline DB calc(DB p1,DB p2)
{
    point X,Y;
    X.x=p1*(B.x-A.x)+A.x; X.y=p1*(B.y-A.y)+A.y;
    Y.x=p2*(D.x-C.x)+C.x; Y.y=p2*(D.y-C.y)+C.y;
    return dis(A,X)/P+dis(X,Y)/R+dis(Y,D)/Q;    
}
inline DB get(DB p1)
{
    DB l=0,r=1.0;
    while (r-l>EPS)
    {
        DB lmid=l+(r-l)/3.0,rmid=r-(r-l)/3.0;
        if (calc(p1,lmid)<=calc(p1,rmid)) r=rmid; else l=lmid;
    }
    return calc(p1,l);
}
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y,&C.x,&C.y,&D.x,&D.y);
        scanf("%d%d%d",&P,&Q,&R);
        DB l=0,r=1.0; 
        while (r-l>EPS)
        {
            DB lmid=l+(r-l)/3.0,rmid=r-(r-l)/3.0;
            if (get(lmid)<=get(rmid)) r=rmid; else l=lmid;
        }
        printf("%.2lf\n",get(l));
    }
    return 0;
}

转载于:https://www.cnblogs.com/cjjsb/p/9179699.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值