Description
Input
Output
Sample Input
Sample Output
题目大意就是先求一个能包含三个点的最小圆,然后判断第四个圆是否在圆内。
这三点中取出两点,如果以这两个点构成的线段为直径,能包含第三个点,自然便是最小圆。于是先考虑最远的两个点即可。
其次,如果上述不满足(三点一线的满足上面),自然需要逐步扩大直径来包含第三个点,自然所求的便是外接圆。
对于求外接圆,此处采用了暴力设圆心坐标(x, y)
所以(x-x1)^2 + (y-y1)^2 = (x-x2)^2 + (y-y2)^2 = (x-x3)^2 + (y-y3)^2
化简得到:
2*((x1-x2)*(y1-y3) - (x1-x3)*(y1-y2)) * x
= (y1-y2)*(y2-y3)*(y1-y3) + (x1*x1-x2*x2)*(y1-y3) - (x1*x1-x3*x3)*(y1-y2);
2*((y1-y2)*(x1-x3) - (y1-y3)*(x1-x2)) * y
= (x1-x2)*(x2-x3)*(x1-x3) + (y1*y1-y2*y2)*(x1-x3) - (y1*y1-y3*y3)*(x1-x2);
于是圆心求出来问题便简单了。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #define LL long long using namespace std; double x1,x2,x3,y1,y2,y3, x0, y0; double rx, ry, r2; int n,i; void Cal() { double A, B; A = 2*((x1-x2)*(y1-y3) - (x1-x3)*(y1-y2)); B = (y1-y2)*(y2-y3)*(y1-y3) + (x1*x1-x2*x2)*(y1-y3) - (x1*x1-x3*x3)*(y1-y2); rx = B/A; A = 2*((y1-y2)*(x1-x3) - (y1-y3)*(x1-x2)); B = (x1-x2)*(x2-x3)*(x1-x3) + (y1*y1-y2*y2)*(x1-x3) - (y1*y1-y3*y3)*(x1-x2); ry = B/A; r2 = (rx-x1)*(rx-x1) + (ry-y1)*(ry-y1); } void Work() { int cnt = 3; double tmp; r2 = ((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))/4; rx = (x1+x2)/2; ry = (y1+y2)/2; tmp = ((x2-x3)*(x2-x3) + (y2-y3)*(y2-y3))/4; if (tmp > r2) { cnt = 1; r2 = tmp; rx = (x3+x2)/2; ry = (y3+y2)/2; } tmp = ((x1-x3)*(x1-x3) + (y1-y3)*(y1-y3))/4; if (tmp > r2) { cnt = 2; r2 = tmp; rx = (x1+x3)/2; ry = (y1+y3)/2; } switch (cnt) { case 1: tmp = (rx-x1)*(rx-x1) + (ry-y1)*(ry-y1); break; case 2: tmp = (rx-x2)*(rx-x2) + (ry-y2)*(ry-y2); break; case 3: tmp = (rx-x3)*(rx-x3) + (ry-y3)*(ry-y3); break; } if (tmp > r2) { Cal(); } } void Output() { if (r2 >= (rx-x0)*(rx-x0) + (ry-y0)*(ry-y0)) printf("Danger\n"); else printf("Safe\n"); } int main() { //freopen("test.in", "r", stdin); int T; scanf("%d", &T); for(int times = 1; times <= T; times++) { scanf("%lf%lf", &x1, &y1); scanf("%lf%lf", &x2, &y2); scanf("%lf%lf", &x3, &y3); scanf("%lf%lf", &x0, &y0); Work(); printf("Case #%d: ", times); Output(); } }