题意:Dw要在充分展现自己枪法的前提下用最少的时间杀死Ly,Dw的枪法的半径为L(在目标点离他距离D<=L他才能射到目标点)。Ly起始坐标为(X1,Y1),且Ly一直以(Lx,Ly)的速度矢量在前进。Dw的起始坐标为(X2,Y2),Dw的速度为vD,子弹的速度为vB。问子弹飞的距离最远为多少,杀死Ly最少要多少秒?
思路:第一个问题感觉很傻逼...因为都说了要充分展现枪法所以子弹飞的最远距离肯定为L。所以子弹飞的时间也确定了为。题目中(Lx*Lx+Ly*Ly)
< vD*vD < vB*vB ,意思是Ly的速度 < Dw速度 < 子弹的速度,所以一定有解。假设Dw花费了
时间杀死Ly(总追击时间),那么Ly的终点为
,因为子弹飞行距离为L,所以子弹的发射点一定在以终点为圆心以L为半径的圆上,共有两种情况如下图:
情况一:d(Dw到终点的距离) = L(子弹飞的距离) + S(Dw跑的距离)
情况二:d(Dw到终点的距离) = L(子弹飞的距离) - S(Dw跑的距离)
Dw必须跑到圆周上才可以进行距离为L的射击,显然最短的一条路为L + S或L - S,子弹飞的时间一定为。Dw跑的时间为
,Dw跑的距离为
。且Dw到终点的距离d可以用
表示为
。Dw要在充分展现枪法的情况下花最短时间内杀死Ly,则有如下两个关于
一元二次方程,我们可以通过二分或解方程得到答案
解方程法:
#include<bits/stdc++.h>
using namespace std;
const double INF = 10000000005.0;
int main()
{
double X1, Y1, X2, Y2, Lx, Ly, vD, vB, L;
while(~scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf", &X1, &Y1, &X2, &Y2, &Lx, &Ly, &vD, &vB, &L))
{
//Ly坐标(X1,Y1)Ly速度矢量(Lx,Ly)
//Dw坐标(X2,Y2)Dw速度vD,枪法半径为L
//子弹速度vB
if(X1 == 0 && Y1 == 0 && X2 == 0 && Y2 == 0 && Lx == 0 && Ly == 0 && vD == 0 && vB == 0 && L == 0) break;
//M,N方便化简
double M = X1 - X2 + L * Lx / vB, N = Y1 - Y2 + L * Ly / vB;
//化简为at^2 + bt + c = 0
double a = pow(Lx, 2) + pow(Ly, 2) - pow(vD, 2),
b1 = 2.0 * Lx * M + 2.0 * Ly * N - 2.0 * L * vD,//L+s的情况
b2 = 2.0 * Lx * M + 2.0 * Ly * N + 2.0 * L * vD,//L-s的情况
c = pow(M, 2) + pow(N, 2) - pow(L, 2);
//求根公式
double t1 = (-b1 + sqrt(pow(b1, 2) - 4.0 * a * c)) / (2.0 * a),
t2 = (-b1 - sqrt(pow(b1, 2) - 4.0 * a * c)) / (2.0 * a),
t3 = (-b2 + sqrt(pow(b2, 2) - 4.0 * a * c)) / (2.0 * a),
t4 = (-b2 - sqrt(pow(b2, 2) - 4.0 * a * c)) / (2.0 * a);
//除掉负数最小的那个就是答案
if(t1 < 0.0) t1 = INF;
if(t2 < 0.0) t2 = INF;
if(t3 < 0.0) t3 = INF;
if(t4 < 0.0) t4 = INF;
printf("%.3lf %.3lf\n", L, min(min(t1,t2), min(t3,t4)) + L / vB);
}
return 0;
}
二分法:
#include<bits/stdc++.h>
using namespace std;
const double eps = 1e-8;//精度
double X1, Y1, X2, Y2, Lx, Ly, vD, vB, L;
double distance(double x1, double y1, double x2, double y2)//两点间距离
{
return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}
double check(double t)
{
double x = X1 + Lx * t, y = Y1 + Ly * t;//t秒后Ly所在位置 即 终点
double d = distance(X2, Y2, x, y);//Dw的起点与Ly的终点间距离
double s = (t - (L / vB)) * vD;//Dw能跑的距离
if(d <= L)//Dw在以终点为圆心以L为半径的圆里面 即L - s
{
if(d < L - s) return false;//跑不到L划的圆上
return true;//能跑到
}
else//在圆外 即L + s
{
if(d > L + s) return false;//跑不到L划的圆上
return true;//能跑到
}
}
int main()
{
while(~scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf", &X1, &Y1, &X2, &Y2, &Lx, &Ly, &vD, &vB, &L))
{
if(X1 == 0 && Y1 == 0 && X2 == 0 && Y2 == 0 && Lx == 0 && Ly == 0 && vD == 0 && vB == 0 && L == 0) break;
//二分时间t
double l = 0, r = 1000000.0, m = l + (r - l) / 2.0;
while(r - l > eps)
{
if(check(m)) r = m;
else l = m;
m = l + (r - l) / 2.0;
}
printf("%.3lf %.3lf\n", L, m);
}
return 0;
}
/*
-1 0 0 10 1 0 2 10 10
0 0 0 5 0 1 2 6 6
0 0 0 0 0 0 0 0 0
*/