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

来源:互联网 发布:linux 重启定时任务 编辑:程序博客网 时间:2024/06/06 18:35

题目大意:

输入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;
}

 

原创粉丝点击