Naive and Silly Muggles
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1123 Accepted Submission(s): 749
Problem Description
Three wizards are doing a experiment. To avoid from bothering, a special magic is set around them. The magic forms a circle, which covers those three wizards, in other words, all of them are inside or on the border of the circle. And due to save the magic power, circle's area should as smaller as it could be.
Naive and silly "muggles"(who have no talents in magic) should absolutely not get into the circle, nor even on its border, or they will be in danger.
Given the position of a muggle, is he safe, or in serious danger?
Input
The first line has a number T (T <= 10) , indicating the number of test cases.
For each test case there are four lines. Three lines come each with two integers xi and yi (|xi, yi| <= 10), indicating the three wizards' positions. Then a single line with two numbers qx and qy (|qx, qy| <= 10), indicating the muggle's position.
Output
For test case X, output "Case #X: " first, then output "Danger" or "Safe".
Sample Input
3 0 0 2 0 1 2 1 -0.5 0 0 2 0 1 2 1 -0.6 0 0 3 0 1 1 1 -1.5
Sample Output
Case #1: Danger Case #2: Safe Case #3: Safe
题意即时让你求三点的最小覆盖圆,其中有一点就是当这三点构成的三角形是钝角三角形的时候,最小覆盖圆的圆心为最长边两点的中点,半径为最长边的一半。
可以将三点引申思考为三角形的外接圆,考虑每种情况,然后在特殊情况特殊处理。
我自己的做法是用高中的知识来求非特殊情况的圆心;
如果这两个点的斜率的负倒数不存在,那么可以交换这两个值;使得处理的这两个点有解。
#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define endl '\n'
#define me(x) memset(x,0,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,-1,-1,1,1};
const int dy[]={0,1,0,-1,1,-1,1,-1};
const int maxn=1e3+5;
const int maxx=1e7+1;
const double EPS=1e-7;
const int mod=1000000007;
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
struct node
{
double x, y;
};
double getk(node a, node b)
{
if(a.x == b.x)
return 0.0;
return (b.x - a.x) / (b.y - a.y) * -1;
}
double dist(node a, node b)
{
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int main()
{
int t;
scanf("%d", &t);
for(int i = 1; i <= t; i++)
{
node a, b, c, p;
scanf("%lf %lf", &a.x, &a.y);
scanf("%lf %lf", &b.x, &b.y);
scanf("%lf %lf", &c.x, &c.y);
scanf("%lf %lf", &p.x, &p.y);
if(a.y == b.y)
swap(b,c);
if(b.y == c.y)
swap(a,b);
double k0 = getk(a, b);
double k1 = getk(b, c);
node cc, p0, p1;
p0.x = 0.5 * (a.x + b.x);
p0.y = 0.5 * (a.y + b.y);
p1.x = 0.5 * (b.x + c.x);
p1.y = 0.5 * (b.y + c.y);
cc.x = (k0 * p0.x - p0.y - k1 * p1.x + p1.y) / (k0 - k1);
cc.y = k0 * (cc.x - p0.x) + p0.y;
double r = (cc.x-a.x)*(cc.x-a.x) + (cc.y-a.y)*(cc.y-a.y);
double ab = dist(a,b);
double bc = dist(b,c);
double ac = dist(a,c);
double maxx = max(ab, bc, ac);
int flag = 1;
if(maxx == ab && ((bc*bc+ac*ac-ab*ab)/2*bc*ac < 0))
{
flag = 0;
cc.x = 0.5 * (a.x + b.x);
cc.y = 0.5 * (a.y + b.y);
r = ab / 2 * ab / 2;
}
else if(maxx == bc && ((ab*ab+ac*ac-bc*bc)/2*ab*ac < 0))
{
flag = 0;
cc.x = 0.5 * (b.x + c.x);
cc.y = 0.5 * (b.y + c.y);
r = bc * bc / 4;
}
else if(maxx == ac && ((ab*ab+bc*bc-ac*ac)/2*ab*bc < 0))
{
flag = 0;
cc.x = 0.5 * (a.x + c.x);
cc.y = 0.5 * (a.y + c.y);
r = ac * ac / 4;
}
if((cc.x-p.x)*(cc.x-p.x) + (cc.y-p.y)*(cc.y-p.y) - r < EPS)
printf("Case #%d: Danger\n", i);
else
printf("Case #%d: Safe\n", i);
}
return 0;
}
另外还有一种求非特殊情况圆的圆心的公式;
(x0,y0)为圆心坐标:
x0 = ((y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1)+(y2-y1)*(y1*y1-y3*y3+x1*x1-x3*x3))/(2*(x2-x1)*(y3-y1)-2*(x3-x1)*(y2-y1));
y0 = ((x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1)+(x2-x1)*(x1*x1-x3*x3+y1*y1-y3*y3))/(2*(y2-y1)*(x3-x1)-2 *(y3-y1)*(x2-x1));
这是求圆心坐标的公式,自己记住再写一遍也许可以理解一些。
已知三个点的坐标是:(x1,y1),(x2,y2), (x3,y3);
#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define endl '\n'
#define me(x) memset(x,0,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,-1,-1,1,1};
const int dy[]={0,1,0,-1,1,-1,1,-1};
const int maxn=1e3+5;
const int maxx=1e7+1;
const double EPS=1e-7;
const int mod=1000000007;
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
int main()
{
int t;
scanf("%d",&t);
int Case=1;
while(t--)
{
double x,y,x3,x1,x2,y3,y1,y2,a,b,r2;
scanf("%lf%lf",&x1,&y1);
scanf("%lf%lf",&x2,&y2);
scanf("%lf%lf",&x3,&y3);
scanf("%lf%lf",&x,&y);
// 用向量点积来判断
if((x2-x1)*(x3-x1)+(y2-y1)*(y3-y1)<0) //(x1,y1)是钝角
{
a=(x3+x2)/2.0,b=(y3+y2)/2.0;
r2=(a-x2)*(a-x2)+(b-y2)*(b-y2);
}
else if((x1-x2)*(x3-x2)+(y1-y2)*(y3-y2)<0) //(x2,y2)是钝角
{
a=(x3+x1)/2.0,b=(y3+y1)/2.0;
r2=(a-x1)*(a-x1)+(b-y1)*(b-y1);
}
else if((x1-x3)*(x2-x3)+(y1-y3)*(y2-y3)<0) //(x3,y3)是钝角
{
a=(x2+x1)/2.0,b=(y2+y1)/2.0;
r2=(a-x1)*(a-x1)+(b-y1)*(b-y1);
}
else //三角形是锐角三角形
{
a=((y2-y1)*(y3*y3-y1*y1+x3*x3-x1*x1)-(y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1))/(2.0*((x3-x1)*(y2-y1)-(x2-x1)*(y3-y1)));
b=((x2-x1)*(x3*x3-x1*x1+y3*y3-y1*y1)-(x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1))/(2.0*((y3-y1)*(x2-x1)-(y2-y1)*(x3-x1)));
r2=(x1-a)*(x1-a)+(y1-b)*(y1-b);
}
if((x-a)*(x-a)+(y-b)*(y-b)<=r2)
printf("Case #%d: Danger\n",Case++);
else
printf("Case #%d: Safe\n",Case++);
}
return 0;
}
还有一种参考网上的方法求这个点的重心(是不是重心?)
具体原理我也不知道
#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define endl '\n'
#define me(x) memset(x,0,sizeof(x));
#define foreach(it,a) for(__typeof((a).begin()) it=(a).begin();it!=(a).end();it++)
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define FORD(i,a,b) for(int i=(a);i<=(b);i++)
#define REP(i,b) FOR(i,0,b)
#define CLR(a) memset(a,0,sizeof(a))
typedef long long LL;
const int INF=0x3f3f3f3f;
const LL LINF=0x3f3f3f3f3f3f3f3fLL;
const int dx[]={-1,0,1,0,-1,-1,1,1};
const int dy[]={0,1,0,-1,1,-1,1,-1};
const int maxn=1e3+5;
const int maxx=1e7+1;
const double EPS=1e-7;
const int mod=1000000007;
template<class T>inline T min(T a,T b,T c) { return min(min(a,b),c);}
template<class T>inline T max(T a,T b,T c) { return max(max(a,b),c);}
template<class T>inline T min(T a,T b,T c,T d) { return min(min(a,b),min(c,d));}
template<class T>inline T max(T a,T b,T c,T d) { return max(max(a,b),max(c,d));}
int main(){
int t;
scanf("%d",&t);
REP(ti,t)
{
double x1,x2,x3,y1,y2,y3;
double lx,ly,rx,ry;
scanf("%lf %lf",&x1,&y1);
scanf("%lf %lf",&x2,&y2);
scanf("%lf %lf",&x3,&y3);
scanf("%lf %lf",&lx,&ly);
rx=(x1+x2+x3)/3.0;
ry=(y1+y2+y3)/3.0;
double r=sqrt((rx-x1)*(rx-x1)+(ry-y1)*(ry-y1));
double leng=sqrt((rx-lx)*(rx-lx)+(ry-ly)*(ry-ly));
if(r>=leng)printf("Case #%d: Danger\n",ti+1);
else printf("Case #%d: Safe\n",ti+1);
}
return 0;
}