CSU-ACM2017暑期训练5-三分 E - Line belt

E - Line belt

 In a two-dimensional plane there are two line belts, there are two segments AB and CD, lxhgww's speed on AB is P and on CD is Q, he can move with the speed R on other area on the plane.
How long must he take to travel from A to D? 

Input

The first line is the case number T.
For each case, there are three lines.
The first line, four integers, the coordinates of A and B: Ax Ay Bx By.
The second line , four integers, the coordinates of C and D:Cx Cy Dx Dy.
The third line, three integers, P Q R.
0<= Ax,Ay,Bx,By,Cx,Cy,Dx,Dy<=1000
1<=P,Q,R<=10

Output

The minimum time to travel from A to D, round to two decimals.

Sample Input

1
0 0 0 100
100 0 100 100
2 2 1

Sample Output

136.60

显然,线段 AB 上一定存在一点 M , 线段 CD 上一定存在一点 N,使得总的行进时间最短。
为此,需要分别找出这两个点。由于对于给定的线段 AB 和线段 CD 都有确定的点 M、点 N 令总耗时最少,可以知道只要枚举出的 AB 上的点 P 偏离了 M, 或 CD 上的点 Q 偏离了 N,总耗时就会长于最短耗时。而当 P 越接近 M 时,对这个 P 而言耗时最短的 Q 也越接近 N
于是,对线段 AB 进行三分查找,得到两个中间值,基于它们,对线段 CD 进行三分查找, 分别得到两个中间值的时间耗费,比较它们,继续对 AB 的三分查找,直到确定点 M 和点 N

Created with Raphaël 2.1.0 开始 对AB三分,中介值E、F,端点left、right 对CD三分,得到点Q,路径 1:A->E->Q->D 对CD三分,得到点Q',路径 2:A->F->Q'->D 依据路径1、2,缩小left和right的间距 left、right离得足够近 得到结果 yes no
#include <iostream>
#include <cstdio>
#include <math.h>
#include <iomanip>
//#define TEST
#define PREC 1e-8
using namespace std;
struct point{
    double x, y;
}a, b, c, d;
double P, Q, R;
double dist(point a, point b){
    return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}

double secondTS(point last){
    point left = d, right = c, mid, midmid;
    double t1, t2;
    do{
        mid.x = (left.x + right.x)/ 2, mid.y = (left.y + right.y) / 2;
        midmid.x = (mid.x + right.x) / 2, midmid.y = (mid.y + right.y) / 2;
        double d1 = dist(mid, last), d2 = dist(midmid, last);
        double dM = dist(mid, d), dN = dist(midmid, d);
        t1 = d1/R + dM/Q, t2 = d2/R + dN/Q;
        if(t1 < t2)
            right = midmid;
        else
            left = mid;
    }while(dist(left, right) > PREC);
    return t1;
}

double firstTS(){
    point left = a, right = b, mid, midmid;
    double t1, t2;
    do{
        mid.x = (left.x + right.x)/ 2, mid.y = (left.y + right.y) / 2;
        midmid.x = (mid.x + right.x) / 2, midmid.y = (mid.y + right.y) / 2;
        double d1 = dist(mid, a), d2 = dist(midmid, a);
        t1 = d1 / P + secondTS(mid), t2 = d2 / P + secondTS(midmid);
        if(t1 < t2)
            right = midmid;
        else
            left = mid;
    }while(dist(left, right) > PREC);
    return t1;
}

int main(){
#ifdef TEST
freopen("test.txt", "r", stdin);
#endif // TEST

    int T;
    while(cin >> T){
        for(int t = 0; t < T; t++){
            cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y >> d.x >> d.y >> P >> Q >> R;
            double res = round(firstTS() * 100) / 100;
            cout << fixed << setprecision(2) << res << endl;
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值