这。。。。。这题难道自带“错误题意引导”???为啥我就算读对了题意,想对了做法,结果敲的时候又按照错误的想法敲了呢?伤不起。。
其实04题才是本场最水题,但是- -题意太坑爹了。唉。
题意:
二维平面追击。
被追击的人有起始坐标,有一个速度矢量,从开始就一直在走。
追击者有起始坐标,有运动速率,射出的子弹也有一个速率。子弹有一个有效射击半径。
就问,在子弹飞行距离最远的情况下,让总追击时间(被追击者被击中前的运动时间)最短,最远距离是多少,最短时间是多少。(一直搞反了题意。妹的。)
条件保证,1e9的时间内一定有解,被追者速率<追者速率<子弹速率。
第二个条件保证了,时间短的时候打不中的话,将时间拉长就一定能打中。
做法:
由于一定有解,为了让飞行距离最长,那么就让它等于射击半径。
果断二分总时间。
得出被追者当前坐标,算出与追击者起始坐标的距离。以射击半径画圆,判断追击者是在圆内还是圆外。并算出小圆半径(即去除子弹时间的剩余时间乘以追击者的运动速率)。判断两圆状态,相离或相切则l = mid,相交则r=mid。(前者表示打不着还需要继续跑,后者表示打到了但不是最优所以要缩短)。
二分中间的某些状态大概可以表示追击者跑到某个地方停了下来,然后等被追击者跑到指定位置再开始秀枪法;但鉴于最优解一定不需要让追击者有等待时间,所以最后的最优状态一定是相切的。
话说因为不小心用到了除法,所以eps开到1e-6会被卡精度,所以没办法只能1e-8了。。第一次写的时候开到1e-6竟然连样例都有精度差,这。。。
唉,被题意坑啊,自己脑子笨,想不清楚二分啊,我弱爆了。
附代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const double eps = 1e-6;
const double inf = 1e9;
int comp(double x)
{
if(fabs(x) < eps)
return 0;
else if(x < -eps)
return -1;
else
return 1;
}
struct point
{
double x,y;
point(){}
point(double a,double b):x(a),y(b){}
point operator - (const point p)
{
return point(x - p.x,y - p.y);
}
point operator *(const double a)
{
return point(x * a,y * a);
}
point operator +(const point p)
{
return point(x + p.x,y + p.y);
}
double norm()
{
return sqrt(x * x + y * y);
}
}p1,p2,L;
double vd,vb,limit;
int main()
{
while(scanf("%lf %lf %lf %lf %lf %lf %lf %lf %lf",&p1.x,&p1.y,&p2.x,&p2.y,&L.x,&L.y,&vd,&vb,&limit) == 9)
{
if(!comp(p1.x) && !comp(p1.y) && !comp(p2.x) && !comp(p2.y) && !comp(L.x) && !comp(L.y) && !comp(vd) && !comp(vb) && !comp(limit))
break;
double t2 = limit / vb;
double l = 0.0,r = inf,mid;
while(comp(l - r) < 0)
{
mid = (l + r) / 2.0;
point now = p1 + L * mid;
if(comp(t2 - mid) > 0)
{
l = mid;
continue;
}
double d = (now - p2).norm();
double most = (mid - t2) * vd;
if(comp(d - limit) <= 0)
{
if(comp(d + most - limit) < 0)
l = mid;
else
r = mid;
}
else
{
if(comp(most + limit - d) < 0)
l = mid;
else
r = mid;
}
}
printf("%.3lf %.3lf\n",limit,mid);
}
}
å