给出圆的圆心和半径,以及三角形的三个顶点,问圆同三角形是否相交。相交输出"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
板子来源
#include<bits/stdc++.h>
using namespace std;
struct Point{//点
double x,y;
Point(){};
Point(double x,double y):x(x),y(y){}
Point operator - (const Point &a)const //向量减
{
return Point(x-a.x,y-a.y);
}
double operator ^(const Point &a)const//向量积sin
{
return x*a.y-y*a.x;
}
double operator *(const Point &a)const//点积cos
{
return x*a.x+y*a.y;
}
};
struct Circle{//圆
double x,y,r;
Circle(){}
Circle(double x,double y,double r):x(x),y(y),r(r){}
};
//默认 是 返还true 否 返回false
bool Cross(const Point&p1,const Point&p2,const Point&p3,const Point&p4)
{
//判断向量p1p2是否跨立p3p4
double a1=(p3-p1)^(p2-p1);
double a2=(p4-p1)^(p2-p1);
if(a1*a2>0)//同向
return false;
return true;
}
//判断线段p1p2与圆是否相交
bool Lcc(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;
//判断点p1是否在圆内
bool flag2=(p2.x-c.x)*(p2.x-c.x)+(p2.y-c.y)*(p2.y-c.y)<=c.r*c.r;
//判断点p2是否在圆内
if(flag1&&flag2)//两点都在圆内,不相交
return false;
if(flag1||flag2)//一点在圆内,一点在圆外,相交
return true;
//两点在圆外,判断形成的线段是否与圆相交
double A,B,C,dis1,dis2,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的距离是否大于半径
dis1=A*c.x+B*c.y+C;
dis1*=dis1;
dis2=(A*A+B*B)*c.r*c.r;
if(dis1>dis2)//距离大于半径
return false;
angle1=(c.x-p1.x)*(p2.x-p1.x)+(c.y-p1.y)*(p2.y-p1.y);//c-p1与p1p2夹角
angle2=(c.x-p2.x)*(p1.x-p2.x)+(c.y-p2.y)*(p1.y-p2.y);//c-p2与p1p2夹角
if(angle1>0&&angle2>0)//都是锐角 相交
return true;
return false;
}
int main()
{
int t;
cin>>t;
while(t--)
{
Point p1,p2,p3;
Circle c;
cin>>c.x>>c.y>>c.r;
cin>>p1.x>>p1.y>>p2.x>>p2.y>>p3.x>>p3.y;
if(Lcc(p1,p2,c)||Lcc(p2,p3,c)||Lcc(p1,p3,c))
cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}