题意: 有6个小题...
(1)给定三角形, 求外接圆
(2)给定三角形, 求内切圆
(3)给定一个点和一个圆, 求所有切线的极角(0 ~180)
(4)给定点P, 直线L和一个半径值r, 求所有过P, 与L相切的半径为r的圆心位置
(5)给定两条不平行直线和半径r, 求与两条线都相切的半径为r的圆心位置
(6)给定两个相离的圆和半径r, 求与两圆都外切的半径为r的圆心位置
解题思路不想说了, 反正我也是东拼西凑才过了的...一开始(3)对atan2不熟悉, 把取值范围搞错了(以为和atan一样), 结果挂了. 以及(2)内切圆也有问题, 如果用角平分线的方法, 求出角度之后还需要判断旋转方向(可以用叉乘), 然而起初没有注意, 结果又挂了. 不过在网上找答案时看到了不错的求法(坐标公式)(其实《训练指南》上面也有), 以后求内切圆就省事多了~
以及这个解决负0的方法也不太令人满意...然而我在别人的正解里也木有看到好的方法(我看的别人的版本似乎只对(3)做了处理, 然后也过了...)
这题也没啥意思, 主要是当作一个代码仓库吧
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <iomanip>
#include <algorithm>
#define eps 1e-8
using namespace std;
struct Point
{
double x,y;
Point(double _x, double _y):x(_x), y(_y)
{}
};
struct Circle
{
Point c;
double r;
Circle(Point _c, double _r):c(_c), r(_r)
{}
Point getPoint(double ang)
{
return Point(c.x + r * cos(ang), c.y + r * sin(ang));
}
};
typedef Point Vector;
/* operators */
Vector operator+(Vector a, Vector b)
{
return Vector(a.x + b.x, a.y + b.y);
}
Vector operator-(Vector a, Vector b)
{
return Vector(a.x - b.x, a.y - b.y);
}
Vector operator*(Vector a, double k)
{
return Vector(a.x * k, a.y * k);
}
Vector operator*(double k, Vector a)
{
return Vector(a.x * k, a.y * k);
}
Vector operator/(Vector a, double k)
{
return Vector(a.x / k, a.y / k);
}
bool operator<(Point a, Point b)
{
if(fabs(a.x - b.x) > eps) return a.x < b.x;
return a.y < b.y;
}
ostream& operator<<(ostream& o, Point p)
{
o <<'(' <<p.x <<',' <<p.y <<')';
return o;
}
double norm(double d)
{
if(fabs(d) < eps) return 0.0;
else return d;
}
Point norm(Point p)
{
return Point(norm(p.x), norm(p.y));
}
template <class T>
void printList(vector<T> vec)
{
cout <<'[';
if(vec.size() > 0)
{
cout <<norm(vec[0]);
for(int i = 1; i < vec.size(); i++)
cout <<',' <<norm(vec[i]);
}
cout <<']' <<endl;
}
/* common operations */
double Dot(Vector A, Vector B)
{
return A.x * B.x + A.y * B.y;
}
double Cross(Vector A, Vector B)
{
return A.x * B.y - A.y * B.x;
}
double Length(Vector A)
{
return sqrt(Dot(A, A));
}
double Angle(Vector A, Vector B)
{
return acos(Dot(A, B) / Length(A) / Length(B));
}
Vector Rotate(Vector A, double t)
{
double nx = A.x * cos(t) - A.y * sin(t);
double ny = A.x * sin(t) + A.y * cos(t);
return Vector(nx, ny);
}
double PolarAngle(Vector A)
{
return atan2(A.y, A.x);
}
Point Intersect(Point A, Vector v, Point B, Vector w)
{
Vector u = A - B;
double t = Cross(w, u) / Cross(v, w);
return A + v*t;
}
double Distance(Point P, Point A, Vector v)
{
return fabs(Cross(P - A, v) / Length(v));
}
double ArcToAngle(double arg)
{
return arg / M_PI * 180;
}
int CLIntersect(Circle C, Point A, Vector v, vector<Point>& ans)
{
double dist = Distance(C.c, A, v);
if(fabs(dist - C.r) < eps) //tangent
{
Vector c(v.y, -v.x);
Point H = Intersect(C.c, c, A, v);
ans.push_back(H);
return 1;
}
else if(dist > C.r) //disjoint
{
return 0;
}
else //cross
{
Vector c(v.y, -v.x);
Point H = Intersect(C.c, c, A, v);
double l = sqrt(C.r * C.r - dist * dist);
Point p1 = H + v / Length(v) * l;
Point p2 = H - v / Length(v) * l;
ans.push_back(p1);
ans.push_back(p2);
return 2;
}
}
/* end of geometry headers */
Circle CsCircle(Point A, Point B, Point C)
{
Point D = (A + B) / 2;
Vector AB = B - A;
Vector d(AB.y, -AB.x);
Point E = (A + C) / 2;
Vector AC = C - A;
Vector e(AC.y, -AC.x);
Point M = Intersect(D, d, E, e);
double r = Length(M - A);
return Circle(M, r);
}
Circle IsCircle(Point A, Point B, Point C)
{
double a = Length(C-B);
double b = Length(A-C);
double c = Length(B-A);
Point M = (A * a + B * b + C * c) / (a + b + c);
double r = Distance(M, A, B-A);
return Circle(M, r);
}
int TangentThroughP(Circle C, Point P, vector<double>& ans)
{
Vector PC = C.c - P;
double dist = Length(PC);
if(fabs(dist - C.r) < eps) //on the circle
{
double ang = PolarAngle(Vector(PC.y, -PC.x));
ans.push_back(ang);
return 1;
}
else if(dist < C.r) //in the circle
{
return 0;
}
else //outside the circle
{
double t = asin(C.r / dist);
double ang = PolarAngle(PC);
double t1 = ArcToAngle(ang + t);
while(t1 > 180 - eps) t1 -= 180;
while(t1 < eps) t1 += 180;
double t2 = ArcToAngle(ang - t);
while(t2 > 180 - eps) t2 -= 180;
while(t2 < eps) t2 += 180;
ans.push_back(t1);
ans.push_back(t2);
return 2;
}
}
int CirclePL(Point P, Point A, Vector v, double r, vector<Point>& ans)
{
double dist = Distance(P, A, v);
Vector p(v.y, -v.x);
if(fabs(dist - 2*r) < eps) //dist == 2r, 1 ans
{
Point H = Intersect(P, p, A, v);
ans.push_back((P + H) / 2);
return 1;
}
else if(fabs(dist) < eps) //on line, 2 ans
{
p = p / Length(p) * r;
ans.push_back(P + p);
ans.push_back(P - p);
return 2;
}
else
{
int cnt = 0;
p = p / Length(p) * r;
cnt += CLIntersect(Circle(P, r), A + p, v, ans);
cnt += CLIntersect(Circle(P, r), A - p, v, ans);
return cnt;
}
}
int CircleLL(Point A, Vector v, Point B, Vector w, double r, vector<Point>& ans)
{
Vector ha = Vector(v.y, -v.x) / Length(v) * r;
Vector hb = Vector(w.y, -w.x) / Length(w) * r;
ans.push_back(Intersect(A + ha, v, B + hb, w));
ans.push_back(Intersect(A - ha, v, B + hb, w));
ans.push_back(Intersect(A + ha, v, B - hb, w));
ans.push_back(Intersect(A - ha, v, B - hb, w));
return 4;
}
int CircleCC(Circle C1, Circle C2, double r, vector<Point>& ans)
{
double dist = Length(C1.c - C2.c);
if(fabs(dist - C1.r - C2.r - 2*r) < eps) //1 ans
{
Vector c = C2.c - C1.c;
c = c / Length(c);
Point nC = C1.c + c * (C1.r + r);
ans.push_back(nC);
return 1;
}
else if(dist > C1.r + C2.r + 2*r) //no ans
{
return 0;
}
else //2 ans
{
Vector c = C2.c - C1.c;
double ang = PolarAngle(c);
double t = acos( ((C1.r + r)*(C1.r + r) + dist * dist - (C2.r + r)*(C2.r + r)) / (2 * (C1.r + r) * dist) );
double a1 = ang + t;
double a2 = ang - t;
Point p1 = C1.c + Vector(cos(a1), sin(a1)) * (C1.r + r);
Point p2 = C1.c + Vector(cos(a2), sin(a2)) * (C1.r + r);
ans.push_back(p1);
ans.push_back(p2);
return 2;
}
}
int main()
{
cout <<setprecision(6) <<fixed;
string comd;
while(cin >>comd)
{
if(comd == "CircumscribedCircle")
{
double x1,y1,x2,y2,x3,y3;
cin >>x1 >>y1 >>x2 >>y2 >>x3 >>y3;
Point A(x1, y1), B(x2, y2), C(x3, y3);
Circle ansC = CsCircle(A, B, C);
cout <<'(' <<norm(ansC.c.x) <<',' <<norm(ansC.c.y) <<',' <<ansC.r <<')' <<endl;
}
if(comd == "InscribedCircle")
{
double x1,y1,x2,y2,x3,y3;
cin >>x1 >>y1 >>x2 >>y2 >>x3 >>y3;
Point A(x1, y1), B(x2, y2), C(x3, y3);
Circle ansC = IsCircle(A, B, C);
cout <<'(' <<norm(ansC.c.x) <<',' <<norm(ansC.c.y) <<',' <<ansC.r <<')' <<endl;
}
if(comd == "TangentLineThroughPoint")
{
double xc,yc,r,xp,yp;
cin >>xc >>yc >>r >>xp >>yp;
Point P(xp, yp);
Circle C(Point(xc, yc), r);
vector<double> ans;
TangentThroughP(C, P, ans);
sort(ans.begin(), ans.end());
printList(ans);
}
if(comd == "CircleThroughAPointAndTangentToALineWithRadius")
{
double xp,yp,x1,y1,x2,y2,r;
cin >>xp >>yp >>x1 >>y1 >>x2 >>y2 >>r;
Point P(xp, yp);
Point A(x1, y1);
Vector v(x2 - x1, y2 - y1);
vector<Point> ans;
CirclePL(P, A, v, r, ans);
sort(ans.begin(), ans.end());
printList(ans);
}
if(comd == "CircleTangentToTwoLinesWithRadius")
{
double x1,y1,x2,y2,x3,y3,x4,y4,r;
cin >>x1 >>y1 >>x2 >>y2 >>x3 >>y3 >>x4 >>y4 >>r;
Point A(x1, y1);
Vector v(x2 - x1, y2 - y1);
Point B(x3, y3);
Vector w(x4 - x3, y4 - y3);
vector<Point> ans;
CircleLL(A, v, B, w, r, ans);
sort(ans.begin(), ans.end());
printList(ans);
}
if(comd == "CircleTangentToTwoDisjointCirclesWithRadius")
{
double x1,y1,r1,x2,y2,r2,r;
cin >>x1 >>y1 >>r1 >>x2 >>y2 >>r2 >>r;
Circle C1(Point(x1, y1), r1);
Circle C2(Point(x2, y2), r2);
vector<Point> ans;
CircleCC(C1, C2, r, ans);
sort(ans.begin(), ans.end());
printList(ans);
}
}
return 0;
}