题目描述:
F - Help!
Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u
Submit
Status
Practice
HDU 5027
Appoint description:
Description
“Help! Help!”
While walking in the park, you suddenly hear someone shouting for help. You immediately realize that a person has fallen into the lake. As a brave man, you decide to save him.
You are really familiar with the terrain of the park. The park can be regarded as a 2D plane. And the lake is a convex polygon. At current, you are on (Xo, Yo), and the person is on (Xp, Yp). You also know that you can run Vr per second on the land, or swim Vs per second in the lake. Notice that you are allowed to run along the edge of the lake.
You are not good at swimming. You cannot stay in the lake longer than Ts second. And carrying another person will cut down your swimming speed by half.
Can you save the poor guy? What is the minimum time for you to reach him, and carry him back to the border of the lake?
Input
There are several test cases in the input.
The first line contains an integer T (1 <= T <= 20) – the number of test cases.
For each case:
The first line contains three real numbers Ts, Vr, Vs. 0 < Ts < 10 8, 0 < Vs < Vr < 10 8.
The second line contains two real numbers Xo, Yo, indicate the position (Xo, Yo) of you at current.
The third line contains two real numbers Xp, Yp, indicate the position (Xp, Yp) of the person you are going to save.
The forth line contains only one integer N – the number of vertices of the lake. 3 <= N <= 50000.
The follow N lines, each line contains two real numbers x, y, indicating one of the vertex (x, y) of the lake. The vertices of lake are listed in either clockwise or counter-clockwise order.
Each coordinate in the input does not exceed 10 6 by its absolute value. Your position is on the land and the person’s is in the lake.
Output
For each test case, output the minimum time(in seconds) to save the poor person, rounded to two digits after the decimal point. If you cannot save he, output “-1” instead.
Sample Input
2
100 2 1
0 10
0 0
3
-1 1
1 1
0 -1
1 2 1
0 10
0 0
3
-1 1
1 1
0 -1
Sample Output
6.39
-1
题解:
思路很简单.但是计算几何大爱啊….锻炼代码能力和敲代码时的脑容量(内存吧= =)
pre:先从终点找一条最短的出去的边,看能不能跑出去.然后把这个影响减去.
首先根据切点来把图上的点分成可以直接到达的和不能直接到达的.有一个分支注意:如果起点在图上,那么就没有切点.这个之后说.
切点可以画一个图,用叉积来判断.
对于搞出来的两个切点,自己利用上一步的叉积符号定义一个顺序,使得我们可以正确的扫能够直接到达的点(第一部分),不能直接到达的点(第二部分)
对于第一部分:我们枚举每一条线段,三分上面的点. 这里有一个特别需要注意的,我们在水里不能游太长时间是一个大前提,所以线段应该先被一个圆切割一下预处理再三分.
对于第二部分:我们发现要要么是先到切点0,然后绕凸多边形,要么是先到切点1,然后绕凸多边形, 我们分开去做,这样还能顺便满足三分的条件.做的时候因为有先绕的那一段距离,我们可以枚举的时候累加.
对于刚开始点在凸包上的情况,其实相当于都是第二部分的情况.先找到点在哪一个线段上,然后先特殊算一下这条线断上的值,然后跟第二部分一样算一下.
代码本来有一个continue提前打了,使得累计有时候没加上去…唉…continue 以后还是多用 {;} 这个玩意把.
重点:
会点和多边形相切的算法
想到三分和相切之后点的三分
想到在多边形上的特殊情况
想到线段三分前先处理下圆的要求
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const double eps = 1e-4;
const int tim = 100;
const double INF = 1e100;
const int maxn = 50000+100;
int dcmp(double x)
{
if(fabs(x) < eps)
return 0;
if(x > eps)
return 1;
return -1;
}
struct Point
{
double x, y;
Point(double _x = 0, double _y = 0)
{
x = _x;
y = _y;
}
Point operator - (const Point &b)
{
return Point(x-b.x, y-b.y);
}
double operator ^ (const Point &b)
{
return x*b.y-y*b.x;
}
double operator * (const Point &b)
{
return x*b.x+y*b.y;
}
double mo()
{
return sqrt(x*x+y*y);
}
};
double dist(Point a, Point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double dist_Point_to_Line(Point o, Point a, Point b)
{
if(dcmp((a-o)*(b-a))>0 || dcmp((b-o)*(a-b))>0)
{
return min(dist(a, o), dist(b, o));
}
return fabs(((a-o)^(b-o))/(b-a).mo());
}
Point p[maxn], oo, pp;
int qie[maxn], hc, fu[maxn], bg, ed;
int n;
double time_back, time_go;
double vr, vs, time_s_limit;
void getQie()
{
hc = 0;
for(int i = 0; i<n; i++)
{
int j = (i+1)%n;
if(dcmp((p[j]-p[i])^(oo-p[i]))<0)
fu[i] = 0;
else
fu[i] = 1;
}
for(int i = 0; i<n; i++)
{
int j = (i+1)%n;
if(fu[i]!=fu[j])
{
qie[hc] = j;
hc++;
}
}
}
double three_Search_Direct(Point a, Point b)
{
Point ma, mb;
double ansa, ansb;
for(int i = 1; i<=tim; i++)
{
mb.x = (a.x+b.x)/2;
mb.y = (a.y+b.y)/2;
ma.x = (a.x+mb.x)/2;
ma.y = (a.y+mb.y)/2;
ansa = dist(ma, oo)/vr + dist(ma, pp)/vs;
ansb = dist(mb, oo)/vr + dist(mb, pp)/vs;
if(ansa-ansb>0)
a = ma;
else
b = mb;
}
ansa = dist(a, oo)/vr + dist(a, pp)/vs;
return ansa;
}
struct Line
{
Point s, e;
};
bool OnSeg(Point P, Line L)
{
return
dcmp((L.s - P) ^ (L.e - P)) == 0 &&
dcmp((P.x - L.s.x) * (P.x - L.e.x)) <= 0 &&
dcmp((P.y - L.s.y) * (P.y - L.e.y)) <= 0;
}
double three_Search_Undirect(Point a, Point b, double pre, Point pa)
{
Point ma, mb;
double ansa, ansb;
for(int i = 1; i<=tim; i++)
{
mb.x = (a.x+b.x)/2;
mb.y = (a.y+b.y)/2;
ma.x = (a.x+mb.x)/2;
ma.y = (a.y+mb.y)/2;
ansa = (pre+dist(pa, ma))/vr + dist(ma, pp)/vs;
ansb = (pre+dist(pa, mb))/vr + dist(mb, pp)/vs;
if(ansa-ansb>0)
a = ma;
else
b = mb;
}
ansa = (pre+dist(pa, a))/vr + dist(a, pp)/vs;
//printf("&&& %f %f -- %f pre is %f %f %f\n", a.x, a.y, ansa+time_back, pre, pa.x,pa.y);
return ansa;
}
void circle_cross_line(Point a, Point b, double r, int &num, Point *res)
{
double xa = a.x, ya = a.y, xb = b.x, yb = b.y;
double dx = xb - xa, dy = yb - ya;
double A = dx*dx + dy*dy, B = 2 * dx*xa + 2 * dy*ya, C = xa*xa + ya*ya -r*r;
double delta = B*B - 4 * A*C;
if (dcmp(delta)<0)
{
num = 0;
return;
}
if (dcmp(delta) == 0)
{
double t1 = (-B) / (2 * A);
if (dcmp(t1) >= 0 && dcmp(t1 - 1) <= 0)
{
num = 1;
res[0] = Point(xa + t1*dx, ya + t1*dy);
return;
}
else
{
num = 0;
return;
}
}
double t1 = (-B - sqrt(delta)) / (2 * A), t2 = (-B + sqrt(delta)) / (2*A);
num = 0;
if(dcmp(t2)<0 || dcmp(t1-1)>0)
{
num = 0;
}
else
{
double ta = max(0.0, t1), tb = min(1.0, t2);
res[num] = Point(xa + ta*dx, ya + ta*dy);
num++;
res[num] = Point(xa + tb*dx, ya + tb*dy);
num++;
}
}
struct PointX
{
Point p[3];
int num;
};
PointX deal_Line_To_Line(Point a, Point b)
{
//printf("** %f %f\n", a.x, a.y);
//printf("** %f %f\n", b.x, b.y);
PointX t;
//printf("&&& %f\n", time_s_limit*vs);
circle_cross_line(a, b, time_s_limit*vs, t.num, t.p);
return t;
}
void solve()
{
for(int i = 0; i<n; i++)
{
p[i].x -= pp.x;
p[i].y -= pp.y;
}
oo.x -= pp.x;
oo.y -= pp.y;
pp.x = 0;
pp.y = 0;
time_back = time_go = INF;
p[n] = p[0];
for(int i = 0; i<n; i++)
{
time_back = min(time_back, dist_Point_to_Line(pp, p[i], p[i+1])/vs*2.0);
}
if(dcmp(time_back-time_s_limit) > 0)
{
printf("-1\n");
return;
}
//printf("**%f %f\n", time_back, sqrt(5)/5.0);
time_s_limit -= time_back;
getQie();
//printf("**%d\n", hc);
// for(int i = 0;i<2;i++)
// {
// printf("**%f %f\n", p[qie[i]].x, p[qie[i]].y);
// }
if(hc==0)
{
for(int i = 0; i<n; i++)
{
int j = (i+1)%n;
Line t;
t.s = p[i];
t.e = p[j];
if(OnSeg(oo, t))
{
qie[0] = i;
qie[1] = j;
PointX x;
x = deal_Line_To_Line(oo, p[j]);
if(x.num==0)
{
;
}
else if(x.num==1)
{
time_go = min(time_go, dist(oo,x.p[0])/vr+dist(x.p[0],pp)/vs);
}
else
{
time_go = min(time_go, three_Search_Undirect(x.p[0],x.p[1],0,oo));
//printf("time_go %f\n", time_go+time_back);
}
x = deal_Line_To_Line(oo, p[i]);
if(x.num==0)
{
;
}
else if(x.num==1)
{
time_go = min(time_go, dist(oo, x.p[0])/vr+dist(x.p[0],pp)/vs);
}
else
{
time_go = min(time_go, three_Search_Undirect(x.p[0],x.p[1],0,oo));
}
break;
}
}
}
else
{
if(fu[qie[0]]!=0)
swap(qie[0], qie[1]);
//printf("%d %d\n", qie[0], qie[1]);
//printf("time_go %f\n", time_go);
int bg = qie[0], ed = qie[1];
if(bg>ed)
ed+=n;
for(int i = bg; i<ed; i++)
{
int j = i+1;
PointX t = deal_Line_To_Line(p[i%n], p[j%n]);
//printf("*** %d %f %f %f %f\n", t.num, t.p[0].x,t.p[0].y,t.p[1].x,t.p[0].y);
if(t.num==0)
continue;
if(t.num==1)
{
time_go = min(time_go, dist(oo, t.p[0])/vr+dist(t.p[0], pp)/vs);
}
else
{
time_go = min(time_go, three_Search_Direct(t.p[0], t.p[1]));
//printf("---- %f\n", time_go);
}
}
//printf("time_go %f\n", time_go);
}
//printf("****************************%f\n", time_s_limit*3);
bg = qie[1];
ed = qie[0];
double pre = dist(oo, p[bg]);
//printf("mygirl %f\n", dist(oo, p[2]), );
//printf("now %d %d\n", bg, ed);
for(int i = bg; (i)%n!=ed; i++)
{
//printf("iiii %d\n", i);
PointX t = deal_Line_To_Line(p[i%n], p[(i+1)%n]);
if(t.num==0)
{
;
}
else if(t.num==1)
{
time_go = min(time_go, pre+dist(p[i%n], t.p[0])/vr + dist(t.p[0],pp)/vs);
}
else
{
//printf("%f %f %f %f %f\n", t.p[0].x,t.p[0].y,t.p[1].x,t.p[1].y, t.p[1].mo());
time_go = min(time_go, three_Search_Undirect(t.p[0],t.p[1],pre, p[i%n]));
}
//printf("time_go %f\n", time_go+time_back);
pre += dist(p[i%n], p[(i+1)%n]);
}
bg = qie[0];
ed = qie[1];
pre = dist(oo, p[bg]);
//printf("pp %f %f\n", pp.x,pp.y);
//printf("big is %d %d\n", bg, ed);
for(int i = bg; (i+n)%n!=ed; i--)
{
//printf("iiii %d\n", i);
int ii = (i+n)%n;
int jj = (ii-1+n)%n;
PointX t = deal_Line_To_Line(p[ii], p[jj]);
if(t.num==0)
{
;
}
else if(t.num==1)
{
time_go = min(time_go, pre+dist(p[ii], t.p[0])/vr + dist(t.p[0],pp)/vs);
}
else
{
//printf("%f %f %f %f %f\n", t.p[0].x,t.p[0].y,t.p[1].x,t.p[1].y, pre);
time_go = min(time_go, three_Search_Undirect(t.p[0],t.p[1],pre, p[ii]));
}
pre += dist(p[ii], p[jj]);
//printf("---- %d %f\n",ii, time_go);
}
//printf("---- %f\n", time_go);
if(dcmp(time_go-INF)==0)
printf("-1\n");
else
{
printf("%.2f\n", time_go+time_back);
}
}
double poly_area(Point *p, int n)
{
double ans = 0;
for (int i = 1; i <= n - 2; i++)
{
ans += (p[i] - p[0]) ^ (p[i + 1] - p[0]);
}
return ans;
}
int main()
{
//printf("**** %f\n", dist_Point_to_Line(Point(0,0),Point(1,0),Point(2,0)));
// freopen("in.txt", "r", stdin);
int ncase;
scanf("%d", &ncase);
while(ncase--)
{
scanf("%lf%lf%lf", &time_s_limit, &vr, &vs);
scanf("%lf%lf", &oo.x, &oo.y);
scanf("%lf%lf", &pp.x, &pp.y);
scanf("%d", &n);
for(int i = 0; i<n; i++)
{
scanf("%lf%lf", &p[i].x, &p[i].y);
}
double tmp = poly_area(p, n);
if(dcmp(tmp)<0)
{
//printf("asdfasd");
reverse(p, p+n);
}
solve();
//printf("********************* %f\n", 3*sqrt(5));
}
return 0;
}