題目
給出圓的圓心和半徑,以及三角形的三個頂點,問圓同三角形是否相交。相交輸出”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
第一種情況:
這種情況下,我們可以得到,
第二種情況:
這種情況下,可以得到
直線方程
直線方程的標準式是:
代碼
#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;
}