欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

51nod 1298 圆与三角形(几何知识)

程序员文章站 2022-04-01 16:53:19
...

Description

给出圆的圆心和半径,以及三角形的三个顶点,问圆同三角形是否相交。相交输出”Yes”,否则输出”No”。(三角形的面积大于0)。

51nod 1298 圆与三角形(几何知识)
51nod 1298 圆与三角形(几何知识)

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