您的位置:首页 > 其它

ZJU2102 Tables - 计算几何 线段与圆相交

2008-03-28 18:14 447 查看
题目大意:

输入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
;
Point p
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: