51nod 1298 圆与三角形(几何知识)
程序员文章站
2022-04-01 16:53:19
...
Description
给出圆的圆心和半径,以及三角形的三个顶点,问圆同三角形是否相交。相交输出”Yes”,否则输出”No”。(三角形的面积大于0)。
Input
第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)
Output
共T行,对于每组输入数据,相交输出”Yes”,否则输出”No”。
Input示例
2
0 0 10
10 0
15 0
15 5
0 0 10
0 0
5 0
5 5
Output示例
Yes
No
解题思路
将判断圆与三角形是否相交转化为判断圆与三条线段是否相交
可以从三种情况来考虑
1、线段的端点在圆上
2、线段的两个端点一个在圆内,另一个在圆外
3、线段的两个端点都在圆外:
此时,对于两个端点和圆心组成的三角形来说,如果圆外的两个内角存在一个是直角或者是钝角,那么便不可能相交;否则求出圆心到线段的距离(可以借助海伦公式或者向量叉乘求面积),再与半径相比较。
要注意精度问题,总是忘记卡了很久(′д` )…彡…彡
代码实现
#include<bits/stdc++.h>
using namespace std;
#define eps 1e-8
struct Point
{
int x;
int y;
}p[3],origin;
double r;
double dis(Point p1,Point p2)
{
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
bool judge(double a,double b,double c)
{
if(a+b==c) return true; //判断三点共线的情况
if(b+c==a||a+c==b)
return false;
if(a*a>=b*b+c*c||b*b>=a*a+c*c) //若圆外的两个角存在钝角则不可能相交
return false;
double p=(a+b+c)/2;
double s=sqrt(p*(p-a)*(p-b)*(p-c)); //海伦公式求解三角形面积
double h=2*s/c; //圆心与两点组成的线段之间的距离
if(h-r>eps) //注意精度问题
return false;
else
return true;
}
int main()
{
ios::sync_with_stdio(false);
int T;
cin>>T;
Point t1,t2;
double a,b,c;
while(T--)
{
bool flag=false;
cin>>origin.x>>origin.y>>r;
for(int i=0;i<3;i++)
cin>>p[i].x>>p[i].y;
for(int i=0;i<3;i++)
{
t1=p[i],t2=p[(i+1)%3];
a=dis(t1,origin);
b=dis(t2,origin);
c=dis(t1,t2);
if(a<r&&b<r) //若两点均在圆内则不可能相交
continue;
if(a==r||b==r||(a<r&&b>r)||(a>r&&b<r)) //点在圆上或者一点在圆内一点在圆外
{
flag=true;
break;
}
if(judge(a,b,c)) //两点均在圆外
{
flag=true;
break;
}
}
if(flag)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}
上一篇: 51 nod 1298 圆与三角形