您的位置:首页 > 其它

51 nod: 1298 圆与三角形

2017-12-05 19:37 405 查看
题目
Input

Output

Input示例

Output示例

题解

代码

题目

给出圆的圆心和半径,以及三角形的三个顶点,问圆同三角形是否相交。相交输出”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. 其它:相交

对于情况2:

1. 如果圆与任意一条边相交,则相交,对于每条边转入2

2. 对于每一条边,求点到直线距离,如果距离大于半径,无交点,否则,转入3

3. 如果以两个三角形点的为中心的角都是锐角,则相交,否则不相交,具体分析如下:

圆心到线段所在直线距离大于r

这种情况下,直接可以确定该线段与圆无交点



圆心到线段所在直线距离小于r

第一种情况:



这种情况下,我们可以得到,∠OAB=∠OCA+∠COA,由于是垂足,因此∠OCA=90∘,∠OAB>90∘。因此得到对应的向量点乘后小于0。注:不需要考虑A是切点,如果是切点,就已经是前面的第3种情况,直接就判断相交。

第二种情况:



这种情况下,可以得到∠OAC+∠AOC=90∘,因此∠OAC<90∘。同理分析∠OBC。因此这两个角都必须是锐角,即向量点乘后大于0。

直线方程

直线方程的标准式是:Ax+By+C=0。需要对垂直和水平的直线进行特殊的考虑。点到直线的距离的公式是:

|Ax+By+C|A2+B2−−−−−−−√

代码

#include <iostream>
#include <limits>
#include <algorithm>

using namespace std;
using ll = long long;

ll Distance(ll x1, ll y1, ll x2, ll y2)
{
return (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2);
}

bool isSegmentCircle(ll x, ll y, ll r,ll px1, ll py1, ll px2, ll py2)
{
ll a, b, c;     // 直线方程的三个参数
if (px1 == px2)
{
a = 1;
b = 0;
c = -px1;
}
else if (py1 == py2)
{
a = 0;
b = 1;
c = -py1;
}
else
{
a = py2 - py1;
b = px1 - px2;
c = px2*py1 - px1*py2;
}
ll dMax = r*r*(a*a + b*b);
ll dUp = a*x + b*y + c;
dUp = dUp*dUp;      // 点到直线距离
if (dUp > dMax)
return false;
// 向量点乘
ll sita1 = (x - px1)*(px2 - px1) + (y - py1)*(py2 - py1);
ll sita2 = (x - px2)*(px1 - px2) + (y - py2)*(py1 - py2);
if (sita1 > 0 && sita2 > 0)
return true;
return false;
}

bool isInterset(ll x, ll y, ll r, ll posX[], ll posY[])
{
ll d1 = Distance(x, y, posX[0], posY[0]);
ll d2 = Distance(x, y, posX[1], posY[1]);
ll d3 = Distance(x, y, posX[2], posY[2]);
ll d = r*r;
if (d1 < d && d2 < d && d3 < d)
return false;
if (d1 > d && d2 > d && d3>d)
{
bool f = false;
f = f || isSegmentCircle(x, y,r, posX[0], posY[0], posX[1], posY[1]);
f = f || isSegmentCircle(x, y,r, posX[1], posY[1], posX[2], posY[2]);
f = f || isSegmentCircle(x, y,r, posX[2], posY[2], posX[0], posY[0]);
return f;
}
return true;
}

int main()
{
//  freopen("input.txt", "r", stdin);
int T;
cin >> T;
ll x, y, r;
ll posX[3];
ll posY[3];
while (T--)
{
scanf("%lld%lld%lld", &x, &y, &r);
for (int i = 0; i < 3; ++i)
scanf("%lld%lld", &posX[i], &posY[i]);
if (isInterset(x, y, r, posX, posY))
cout << "Yes\n";
else
cout << "No\n";
}
return 0;
}


思路参考自 http://blog.csdn.net/f_zyj/article/details/52066901
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: