51Nod_1298 圆与三角形
http://www.51nod.com/Challenge/Problem.html#!#problemId=1298
题目
给出圆的圆心和半径,以及三角形的三个顶点,问圆同三角形是否相交。相交输出"Yes",否则输出"No"。(三角形的面积大于0)。
输入
第1行:一个数T,表示输入的测试数量(1 <= T <= 10000),之后每4行用来描述一组测试数据。4-1:三个数,前两个数为圆心的坐标xc, yc,第3个数为圆的半径R。(-3000 <= xc, yc <= 3000, 1 <= R <= 3000)。4-2:2个数,三角形第1个点的坐标。4-3:2个数,三角形第2个点的坐标。4-4:2个数,三角形第3个点的坐标。(-3000 <= xi, yi <= 3000)
输出
共T行,对于每组输入数据,相交输出"Yes",否则输出"No"。
样例输入
2
0 0 10
10 0
15 0
15 5
0 0 10
0 0
5 0
5 5
样例输出
Yes
No
分析
化为判断线段与圆是否相交的问题。
C++程序
#include<iostream>
using namespace std;
//点
struct Point{
double x,y;
Point(){}
Point(int x,int y):x(x),y(y){}
};
//圆
struct Circle{
double r,x,y;
Circle(){};
Circle(double r,double x,double y):r(r),x(x),y(y){}
};
//判断直线p1p2与圆c是否相交,相交返回true,否则返回false
bool judge(Point p1,Point p2,Circle c)
{
bool flag1=(p1.x-c.x)*(p1.x-c.x)+(p1.y-c.y)*(p1.y-c.y)<=c.r*c.r;
bool flag2=(p2.x-c.x)*(p2.x-c.x)+(p2.y-c.y)*(p2.y-c.y)<=c.r*c.r;
if(flag1&&flag2) //情况一、两点都在圆内 :一定不相交
return false;
else if(flag1||flag2) //情况二、一个点在圆内,一个点在圆外:一定相交
return true;
else //情况三、两个点都在圆外
{
double A,B,C,dist1,dist2,angle1,angle2;
//将直线p1p2化为一般式:Ax+By+C=0的形式。先化为两点式,然后由两点式得出一般式
A=p1.y-p2.y;
B=p2.x-p1.x;
C=p1.x*p2.y-p2.x*p1.y;
//使用距离公式判断圆心到直线ax+by+c=0的距离是否大于半径
dist1=A*c.x+B*c.y+C;
dist1*=dist1;
dist2=(A*A+B*B)*c.r*c.r;
if(dist1>dist2)//圆心到直线p1p2的距离大于半径,不相交
return false;
angle1=(c.x-p1.x)*(p2.x-p1.x)+(c.y-p1.y)*(p2.y-p1.y);
angle2=(c.x-p2.x)*(p1.x-p2.x)+(c.y-p2.y)*(p1.y-p2.y);
if(angle1>0&&angle2>0)//余弦为正,则是锐角,一定相交
return true;
else
return false;
}
}
int main()
{
int t;
Circle c;//圆
Point p[3];//三角形的三个顶点
scanf("%d",&t);
while(t--)
{
scanf("%lf%lf%lf",&c.x,&c.y,&c.r);//读入圆的圆心和半径
for(int i=0;i<3;i++)//读入三角形的三个顶点
scanf("%lf%lf",&p[i].x,&p[i].y);
//判断3条边是否与圆相交
bool flag1=judge(p[0],p[1],c);
bool flag2=judge(p[1],p[2],c);
bool flag3=judge(p[0],p[2],c);
if(flag1||flag2||flag3)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}