题目大意:
输入n个圆形桌子的圆心和半径(从俯视的角度看),给出一根木棍两端点的坐标,问木棍会不会掉到地上。(n<=10000)假设桌子完全水平,木棍的质量分布均匀。
分析:
设木棍端点为a,b,因为木棍质量分布均匀,所以重心c一定在(a+b)/2处。
1、若重心c点被包放在任何一个桌子上,则木棍不会掉;
2、否则,若重心c两侧分别有一部分放在桌子上,木棍也不会掉。
第一种情况需要判断点是否在圆内,很简单,判断点c到圆心的距离小于等于半径即可。
第二种情况是要分别判断线段ac,cb是否与圆相交,其核心也就是计算圆心到线段的距离。
下面分析如何计算点到线段距离:
假设线段端点为ab,点为p。过p作直线ab的垂线。
1、若ab在垂线同侧,那么距离就是p到直线ab的距离。
2、若ab在垂线两侧,那么距离就是p到最近一个端点的距离。
判断ab在同侧还是异侧可以用向量点乘,pa·pb < 0 异侧; >=0 同侧。
计算点p到直线ab的距离可用向量叉乘,d = (ab×ap) / |ab|。
==================================================
/*
ZJU2102 Tables
*/
#include <stdio.h>
#include <math.h>
#define N 10005
typedef struct{
double x,y;
}Point;
double r[N];
Point p[N];
Point a,b,c;
double dis(Point a,Point b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double dot(Point p1,Point p2,Point p0){
return (p1.x-p0.x)*(p2.x-p0.x) + (p1.y-p0.y)*(p2.y-p0.y);
}
double mul(Point p1,Point p2,Point p0){
return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
}
double Min(double a,double b){
return a>b?b:a;
}
double Abs(double a){
return a>0?a:-a;
}
double disline(Point a,Point b,Point p){
if(dot(a,b,p)<0) return Abs(mul(b,p,a))/dis(a,b);
else return Min(dis(a,p),dis(b,p));
}
int main()
{
int i,j,n;
int flag,fl,fr;
while(scanf("%d",&n),n){
//input
for(i=0;i<n;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&r[i]);
scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
c.x=(a.x+b.x)/2.;
c.y=(a.y+b.y)/2.;
//judge
flag=fr=fl=0;
for(i=n-1;i>=0&&!flag;i--){
if(dis(c,p[i])<=r[i]) flag=1;
else if(disline(a,c,p[i])<=r[i]) fl=1;
else if(disline(c,b,p[i])<=r[i]) fr=1;
if(fl&&fr) flag=1;
}
//output
if(flag) puts("STAY");
else puts("FALL");
}
return 0;
}