【题目描述】
在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段。两条传送带分别为线段AB和线段CD。lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平面上的移动速度R。现在lxhgww想从A点走到D点,他想知道最少需要走多长时间
【输入】
输入数据第一行是4个整数,表示A和B的坐标,分别为Ax,Ay,Bx,By
第二行是4个整数,表示C和D的坐标,分别为Cx,Cy,Dx,Dy
第三行是3个整数,分别是P,Q,R
【输出】
输出数据为一行,表示lxhgww从A点走到D点的最短时间,保留到小数点后2位
【样例输入】
0 0 0 100
100 0 100 100
2 2 1
【样例输出】
136.60
【数据范围】
对于100%的数据,1<= Ax,Ay,Bx,By,Cx,Cy,Dx,Dy<=1000
1<=P,Q,R<=10
代码不算长,只是其中加了个Point类(可供坐标的加减乘除运算),占了一定篇幅。此题考察三分法。
原问题可以抽象成以下问题:
在线段AB上找一点E,在线段CD上找一点F,使得AE / p + EF / r + FD / q最小。
不难看出,E,F点一定是唯一的。
也就是说,关于E,F的目标函数在定义域内一定只有一个极值点。
那么可以直接三分E和F,求得最小值即可。
Accode:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
const double MAX = 1e198;
const double MIN = -MAX;
const double zero = 1e-12;
template <typename _Tp>
class Point
{
private:
_Tp _x, _y;
public:
Point() {_x = _y = 0; }
Point(_Tp x, _Tp y)
{
_x = x;
_y = y;
}
_Tp x();
_Tp y();
Point &operator=(Point p)
{
_x = p.x();
_y = p.y();
return *this;
}
Point operator+(Point b) const
{
Point c(_x + b.x(), _y + b.y());
return c;
}
Point operator-(Point b) const
{
Point c(_x - b.x(), _y - b.y());
return c;
}
Point operator*(_Tp p)
{
Point c(_x * p, _y * p);
return c;
}
Point operator/(_Tp p)
{
Point c(_x / p, _y / p);
return c;
}
Point &operator+=(Point b)
{
_x += b.x();
_y += b.y();
return *this;
}
Point &operator-=(Point b)
{
_x -= b.x();
_y -= b.y();
return *this;
}
Point &operator*=(_Tp p)
{
_x *= p;
_y *= p;
return *this;
}
Point &operator/=(_Tp p)
{
_x /= p;
_y /= p;
return *this;
}
};
int xA, xB, xC, xD, yA, yB, yC, yD;
Point <double> A, B, C, D;
double v1, v2, v3;
template <typename _Tp>
_Tp Point <_Tp> ::x()
{
return _x;
}
template <typename _Tp>
_Tp Point <_Tp> ::y()
{
return _y;
}
double sqr(double x)
{
return x * x;
}
double dist(Point <double> a,
Point <double> b)
{
Point <double> tmp = b - a;
return sqrt(sqr(tmp.x()) + sqr(tmp.y()));
}
double func(Point <double> E,
Point <double> F)
{
return dist(A, E) / v1
+ dist(E, F) / v3
+ dist(F, D) / v2;
}
double Find_F(Point <double> E)
{
Point <double> L = C, R = D, tmp, p, q;
double ans = MAX;
//一切的枚举变量都应使用局部变量。
while (dist(L, R) > zero)
{
tmp = (R - L) / 3;
p = L + tmp;
q = R - tmp;
double fp = func(E, p);
double fq = func(E, q);
if (fp > fq) L = p;
else R = q;
if (fp < ans) ans = fp;
if (fq < ans) ans = fq;
//更新ans的值。
}
if (dist(C, D) < zero) ans = func(E, C);
//特殊处理,当C,D重合时,F取C。
return ans;
}
double Find_E()
{
Point <double> L = A, R = B, tmp, p, q;
double ans = MAX;
//一切的枚举变量都应使用局部变量。
while (dist(L, R) > zero)
{
tmp = (R - L) / 3;
p = L + tmp;
q = R - tmp;
double fp = Find_F(p);
double fq = Find_F(q);
if (fp > fq) L = p;
else R = q;
if (fp < ans) ans = fp;
if (fq < ans) ans = fq;
//更新ans的值。
}
if (dist(A, B) < zero) ans = Find_F(A);
//特殊处理:当A,B重合时,E取A。
return ans;
}
int main()
{
freopen("walk.in", "r", stdin);
freopen("walk.out", "w", stdout);
scanf("%d%d%d%d%d%d%d%d%lf%lf%lf",
&xA, &yA, &xB, &yB, &xC, &yC,
&xD, &yD, &v1, &v2, &v3);
A = Point <double> (xA, yA);
B = Point <double> (xB, yB);
C = Point <double> (xC, yC);
D = Point <double> (xD, yD);
printf("%.2lf\n", Find_E());
return 0;
}