传送带

https://loj.ac/problem/10017

题目描述

  给出两条线段\(AB\)\(CD\),并且给出在线段\(AB\),线段\(CD\),平面上的移动速度,求从\(A\)点到\(B\)点最短的移动时间。

思路

  首先比较容易想到最优的移动路径一定由\(A\)\(AB\)上一点\(P\)\(P\)\(CD\)上一点\(Q\)\(Q\)\(D\)的路径组成。这道题显然应该用三分做,二分是无法过的,因为我们无法保证这个题只是单调增或单调减。但\(P\)\(Q\)都需要三分,我们就需要三分套三分。如果三分\(P、Q\)的横纵坐标,我们会发现代码比较复杂,所以我们可以三分\(AQ\)\(AB\)的比值,以及三分\(CQ\)\(CD\)的比值,这样可以发现码量大大减少了。

代码

#include <bits/stdc++.h>
using namespace std;
double ax,bx,cx,dx,ay,by,cy,dy,p,q,r;
double f(double a,double b,double c,double d)
{
    return sqrt((a-c)*(a-c)+(b-d)*(b-d));
}
double check2(double k1,double k2)
{
    double x1=ax+k1*(bx-ax),y1=ay+k1*(by-ay);
    double x2=cx+k2*(dx-cx),y2=cy+k2*(dy-cy);
    return f(ax,ay,x1,y1)/p+f(x1,y1,x2,y2)/r+f(x2,y2,dx,dy)/q;
}
double check(double k)
{
    double l=0,r=1,eps=1e-5;
    while(r-l>eps)
    {
        double lmid=l+(r-l)/3;
        double rmid=r-(r-l)/3;
        if(check2(k,lmid)<=check2(k,rmid))r=rmid;
        else l=lmid;
    }
    return check2(k,r);
}
int main() 
{
    scanf("%lf%lf%lf%lf",&ax,&ay,&bx,&by);
    scanf("%lf%lf%lf%lf",&cx,&cy,&dx,&dy);
    scanf("%lf%lf%lf",&p,&q,&r);
    double l=0,r=1,eps=1e-5;
    while(r-l>eps)
    {
        double lmid=l+(r-l)/3;
        double rmid=r-(r-l)/3;
        if(check(lmid)<=check(rmid))r=rmid;
        else l=lmid;
    }
    printf("%.2lf",check(r));
    return 0;
}
posted @ 2019-10-29 17:54  fbz  阅读(127)  评论(0编辑  收藏  举报