UVa 12304 (6个二维几何问题合集) 2D Geometry 110 in 1!

时间:2023-03-09 12:49:30
UVa 12304 (6个二维几何问题合集) 2D Geometry 110 in 1!

这个题能1A纯属运气,要是WA掉,可真不知道该怎么去调了。

题意:

这是完全独立的6个子问题。代码中是根据字符串的长度来区分问题编号的。

  1. 给出三角形三点坐标,求外接圆圆心和半径。
  2. 给出三角形三点坐标,求内切圆圆心和半径。
  3. 给出一个圆和一个定点,求过定点作圆的所有切线的倾角(0≤a<180°)
  4. 给出一个点和一条直线,求一个半径为r的过该点且与该直线相切的圆。
  5. 给出两条相交直线,求所有半径为r且与两直线都相切的圆。
  6. 给出两个相离的圆,求半径为r且与两圆都相切的圆。

分析:

  1. 写出三角形两边的垂直平分线的一般方程(注意去掉分母,避免直线是水平或垂直的特殊情况),然后联立求解即可。
  2. 有一个很简洁的三角形内心坐标公式(证明有点复杂,可用向量来证,其中多次用到角平分线定理),公式详见代码。
  3. 分点在圆内,圆上,圆外三种情况,注意最终结果的范围。
  4. 到定点距离为r的轨迹是个圆,与直线相切的圆心的轨迹是两条平行直线。最终转化为求圆与两条平行线的交点。
  5. 我开始用的方法是求出圆心到两直线交点的距离,以及与其中一条直线的夹角,依次旋转三个90°即可得到另外三个点。但是对比正确结果,误差居然达到了个位(如果代码没有错的话)!后来参考了lrj的思路,就是讲两直线分别向两侧平移r距离,这样得到的四条直线两两相交得到的四个交点就是所求。
  6. 看起来有点复杂,仔细分析,半径为r与圆外切的圆心的轨迹还是个圆。因此问题转化为求半径扩大以后的两圆的交点。

体会:

  • (Point)(x, y)是强制类型转换,Point(x, y)才是调用构造函数。前者只会将x的值复制,y的值则是默认值0.
  • 计算的中间步骤越多,误差越大,最好能优化算法,或者调整EPS的大小。
 //#define LOCAL
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std; struct Point
{
double x, y;
Point(double xx=, double yy=) :x(xx),y(yy) {}
};
typedef Point Vector; Point read_point(void)
{
double x, y;
scanf("%lf%lf", &x, &y);
return Point(x, y);
} const double EPS = 1e-;
const double PI = acos(-1.0); 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 p) { return Vector(A.x*p, A.y*p); } Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p); } bool operator < (const Point& a, const Point& b)
{ return a.x < b.x || (a.x == b.x && a.y < b.y); } int dcmp(double x)
{ if(fabs(x) < EPS) return ; else return x < ? - : ; } bool operator == (const Point& a, const Point& b)
{ return dcmp(a.x-b.x) == && dcmp(a.y-b.y) == ; } double Dot(Vector A, Vector B)
{ return A.x*B.x + A.y*B.y; } double Length(Vector A) { return sqrt(Dot(A, A)); } double Angle(Vector A, Vector B)
{ return acos(Dot(A, B) / Length(A) / Length(B)); } double Angle2(Vector A) { return atan2(A.y, A.x); } Vector VRotate(Vector A, double rad)
{
return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));
} Vector Normal(Vector A)
{
double l = Length(A);
return Vector(-A.y/l, A.x/l);
} double Change(double r) { return r / PI * 180.0; } double Cross(Vector A, Vector B)
{ return A.x*B.y - A.y*B.x; } struct Circle
{
double x, y, r;
Circle(double x=, double y=, double r=):x(x), y(y), r(r) {}
Point point(double a)
{
return Point(x+r*cos(a), y+r*sin(a));
}
}; const int maxn = ;
char s[maxn]; int ID(char* s)
{
int l = strlen(s);
switch(l)
{
case : return ;
case : return ;
case : return ;
case : return ;
case : return ;
case : return ;
default: return -;
}
} void Solve(double A1, double B1, double C1, double A2, double B2, double C2, double& ansx, double& ansy)
{
ansx = (B1*C2 - B2*C1) / (A1*B2 - A2*B1);
ansy = (C2*A1 - C1*A2) / (B1*A2 - B2*A1);
} void problem0()
{
Point A, B, C;
scanf("%lf%lf%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y);
double A1 = B.x-A.x, B1 = B.y-A.y, C1 = (A.x*A.x-B.x*B.x+A.y*A.y-B.y*B.y)/;
double A2 = C.x-A.x, B2 = C.y-A.y, C2 = (A.x*A.x-C.x*C.x+A.y*A.y-C.y*C.y)/;
Point ans;
Solve(A1, B1, C1, A2, B2, C2, ans.x, ans.y);
double r = Length(ans - A);
printf("(%.6lf,%.6lf,%.6lf)\n", ans.x, ans.y, r);
} void problem1()
{
Point A, B, C;
scanf("%lf%lf%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y);
double a = Length(B-C), b = Length(A-C), c = Length(A-B);
double l = a+b+c;
Point ans = (A*a+B*b+C*c)/l;
double r = fabs(Cross(A-B, C-B)) / l;
printf("(%.6lf,%.6lf,%.6lf)\n", ans.x, ans.y, r);
} void problem2()
{
Circle C;
Point P, O;
scanf("%lf%lf%lf%lf%lf", &C.x, &C.y, &C.r, &P.x, &P.y);
double ans[];
O.x = C.x, O.y = C.y;
double d = Length(P-O);
int k = dcmp(d-C.r);
if(k < )
{
printf("[]\n");
return;
}
else if(k == )
{
ans[] = Change(Angle2(P-O)) + 90.0;
while(ans[] >= 180.0) ans[] -= 180.0;
while(ans[] < ) ans[] += 180.0;
printf("[%.6lf]\n", ans[]);
return;
}
else
{
double ag = asin(C.r/d);
double base = Angle2(P-O);
ans[] = base + ag, ans[] = base - ag;
ans[] = Change(ans[]), ans[] = Change(ans[]);
while(ans[] >= 180.0) ans[] -= 180.0;
while(ans[] < ) ans[] += 180.0;
while(ans[] >= 180.0) ans[] -= 180.0;
while(ans[] < ) ans[] += 180.0;
if(ans[] >= ans[]) swap(ans[], ans[]);
printf("[%.6lf,%.6lf]\n", ans[], ans[]);
}
} vector<Point> sol;
struct Line
{
Point p;
Vector v;
Line() { }
Line(Point p, Vector v): p(p), v(v) {}
Point point(double t)
{
return p + v*t;
}
Line move(double d)
{
return Line(p + Normal(v)*d, v);
}
};
Point GetIntersection(Line a, Line b)
{
Vector u = a.p - b.p;
double t = Cross(b.v, u) / Cross(a.v, b.v);
return a.p + a.v*t;
}
struct Circle2
{
Point c; //圆心
double r; //半径
Point point(double a)
{
return Point(c.x+r*cos(a), c.y+r*sin(a));
}
};
//两圆相交并返回交点个数
int getLineCircleIntersection(Line L, Circle2 C, vector<Point>& sol)
{
double t1, t2;
double a = L.v.x, b = L.p.x - C.c.x, c = L.v.y, d = L.p.y - C.c.y;
double e = a*a + c*c, f = *(a*b + c*d), g = b*b + d*d - C.r*C.r;
double delta = f*f - *e*g; //判别式
if(dcmp(delta) < ) return ; //相离
if(dcmp(delta) == ) //相切
{
t1 = t2 = -f / ( * e);
sol.push_back(L.point(t1));
return ;
}
//相交
t1 = (-f - sqrt(delta)) / ( * e); sol.push_back(L.point(t1));
t2 = (-f + sqrt(delta)) / ( * e); sol.push_back(L.point(t2));
return ;
}
void problem3()
{
Circle2 C;
Point A, B;
scanf("%lf%lf%lf%lf%lf%lf%lf", &C.c.x, &C.c.y, &A.x, &A.y, &B.x, &B.y, &C.r);
Vector v = (A-B)/Length(A-B)*C.r;
//printf("%lf\n", Length(v));
Point p1 = A + Point(-v.y, v.x);
Point p2 = A + Point(v.y, -v.x);
//printf("%lf\n%lf", Length(p1-C.c), Length(p2-C.c));
Line L1(p1, v), L2(p2, v); sol.clear();
int cnt = getLineCircleIntersection(L1, C, sol);
cnt += getLineCircleIntersection(L2, C, sol);
sort(sol.begin(), sol.end());
if(cnt == ) { printf("[]\n"); return; }
printf("[");
for(int i = ; i < cnt-; ++i) printf("(%.6lf,%.6lf),", sol[i].x, sol[i].y);
printf("(%.6lf,%.6lf)]\n", sol[cnt-].x, sol[cnt-].y);
} void problem4()
{
double r;
Point A, B, C, D, E, ans[];
scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y, &D.x, &D.y, &r);
Line a(A, B-A), b(C, D-C);
Line L1 = a.move(r), L2 = a.move(-r);
Line L3 = b.move(r), L4 = b.move(-r);
ans[] = GetIntersection(L1, L3);
ans[] = GetIntersection(L1, L4);
ans[] = GetIntersection(L2, L3);
ans[] = GetIntersection(L2, L4);
sort(ans, ans+);
printf("[");
for(int i = ; i < ; ++i) printf("(%.6lf,%.6lf),", ans[i].x, ans[i].y);
printf("(%.6lf,%.6lf)]\n", ans[].x, ans[].y);
} int getCircleCircleIntersection(Circle2 C1, Circle2 C2, vector<Point>& sol)
{
double d = Length(C1.c - C2.c);
if(dcmp(d) == )
{
if(dcmp(C1.r - C2.r) == ) return -;
return ;
}
if(dcmp(C1.r + C2.r - d) < ) return ;
if(dcmp(fabs(C1.r - C2.r) - d) > ) return ; double a = Angle2(C2.c - C1.c);
double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (*C1.r*d));
Point p1 = C1.point(a+da), p2 = C1.point(a-da);
sol.push_back(p1);
if(p1 == p2) return ;
sol.push_back(p2);
return ;
} void problem5()
{
Circle2 C1, C2;
double r;
vector<Point> sol;
scanf("%lf%lf%lf%lf%lf%lf%lf", &C1.c.x, &C1.c.y, &C1.r, &C2.c.x, &C2.c.y, &C2.r, &r);
double d = Length(C1.c - C2.c);
C1.r += r, C2.r += r;
if(dcmp(C1.r+C2.r-d) < ) { printf("[]\n"); return; }
int n = getCircleCircleIntersection(C1, C2, sol);
sort(sol.begin(), sol.end());
printf("[");
for(int i = ; i < n-; ++i) printf("(%.6lf,%.6lf),", sol[i].x, sol[i].y);
printf("(%.6lf,%.6lf)]\n", sol[n-].x, sol[n-].y);
} int main()
{
#ifdef LOCAL
freopen("12304in.txt", "r", stdin);
#endif while(scanf("%s", s) == )
{
int proID = ID(s);
switch(proID)
{
case : problem0(); break;
case : problem1(); break;
case : problem2(); break;
case : problem3(); break;
case : problem4(); break;
case : problem5(); break;
default: break;
}
} return ;
}

代码君