zoukankan      html  css  js  c++  java
  • 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的大小。
      1 //#define LOCAL
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <string>
      5 #include <algorithm>
      6 #include <cmath>
      7 #include <vector>
      8 using namespace std;
      9 
     10 struct Point
     11 {
     12     double x, y;
     13     Point(double xx=0, double yy=0) :x(xx),y(yy) {}
     14 };
     15 typedef Point Vector;
     16 
     17 Point read_point(void)
     18 {
     19     double x, y;
     20     scanf("%lf%lf", &x, &y);
     21     return Point(x, y);
     22 }
     23 
     24 const double EPS = 1e-7;
     25 const double PI = acos(-1.0);
     26 
     27 Vector operator + (Vector A, Vector B)    { return Vector(A.x + B.x, A.y + B.y); }
     28 
     29 Vector operator - (Vector A, Vector B)    { return Vector(A.x - B.x, A.y - B.y); }
     30 
     31 Vector operator * (Vector A, double p)    { return Vector(A.x*p, A.y*p); }
     32 
     33 Vector operator / (Vector A, double p)    { return Vector(A.x/p, A.y/p); }
     34 
     35 bool operator < (const Point& a, const Point& b)
     36 { return a.x < b.x || (a.x == b.x && a.y < b.y); }
     37 
     38 int dcmp(double x)
     39 { if(fabs(x) < EPS) return 0; else return x < 0 ? -1 : 1; }
     40 
     41 bool operator == (const Point& a, const Point& b)
     42 { return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0; }
     43 
     44 double Dot(Vector A, Vector B)
     45 { return A.x*B.x + A.y*B.y; }
     46 
     47 double Length(Vector A)    { return sqrt(Dot(A, A)); }
     48 
     49 double Angle(Vector A, Vector B)
     50 { return acos(Dot(A, B) / Length(A) / Length(B)); }
     51 
     52 double Angle2(Vector A)    { return atan2(A.y, A.x); }
     53 
     54 Vector VRotate(Vector A, double rad)
     55 {
     56     return Vector(A.x*cos(rad) - A.y*sin(rad), A.x*sin(rad) + A.y*cos(rad));
     57 }
     58 
     59 Vector Normal(Vector A)
     60 {
     61     double l = Length(A);
     62     return Vector(-A.y/l, A.x/l);
     63 }
     64 
     65 double Change(double r)    { return r / PI * 180.0; }
     66 
     67 double Cross(Vector A, Vector B)
     68 { return A.x*B.y - A.y*B.x; }
     69 
     70 struct Circle
     71 {
     72     double x, y, r;
     73     Circle(double x=0, double y=0, double r=0):x(x), y(y), r(r) {}
     74     Point point(double a)
     75     {
     76         return Point(x+r*cos(a), y+r*sin(a));
     77     }
     78 };
     79 
     80 const int maxn = 1010;
     81 char s[maxn];
     82 
     83 int ID(char* s)
     84 {
     85     int l = strlen(s);
     86     switch(l)
     87     {
     88         case 19: return 0;
     89         case 15: return 1;
     90         case 23: return 2;
     91         case 46: return 3;
     92         case 33: return 4;
     93         case 43: return 5;
     94         default: return -1;
     95     }
     96 }
     97 
     98 void Solve(double A1, double B1, double C1, double A2, double B2, double C2, double& ansx, double& ansy)
     99 {
    100     ansx = (B1*C2 - B2*C1) / (A1*B2 - A2*B1);
    101     ansy = (C2*A1 - C1*A2) / (B1*A2 - B2*A1);    
    102 }
    103 
    104 void problem0()
    105 {
    106     Point A, B, C;
    107     scanf("%lf%lf%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y);
    108     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)/2;
    109     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)/2;
    110     Point ans;
    111     Solve(A1, B1, C1, A2, B2, C2, ans.x, ans.y);
    112     double r = Length(ans - A);
    113     printf("(%.6lf,%.6lf,%.6lf)
    ", ans.x, ans.y, r);
    114 }
    115 
    116 void problem1()
    117 {
    118     Point A, B, C;
    119     scanf("%lf%lf%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y);
    120     double a = Length(B-C), b = Length(A-C), c = Length(A-B);
    121     double l = a+b+c;
    122     Point ans = (A*a+B*b+C*c)/l;
    123     double r = fabs(Cross(A-B, C-B)) / l;
    124     printf("(%.6lf,%.6lf,%.6lf)
    ", ans.x, ans.y, r);
    125 }
    126 
    127 void problem2()
    128 {
    129     Circle C;
    130     Point P, O;
    131     scanf("%lf%lf%lf%lf%lf", &C.x, &C.y, &C.r, &P.x, &P.y);
    132     double ans[2];
    133     O.x = C.x, O.y = C.y;
    134     double d = Length(P-O);
    135     int k = dcmp(d-C.r);
    136     if(k < 0)
    137     {
    138         printf("[]
    ");
    139         return;
    140     }
    141     else if(k == 0)
    142     {
    143         ans[0] = Change(Angle2(P-O)) + 90.0;
    144         while(ans[0] >= 180.0)    ans[0] -= 180.0;
    145         while(ans[0] < 0)        ans[0] += 180.0;
    146         printf("[%.6lf]
    ", ans[0]);
    147         return;
    148     }
    149     else
    150     {
    151         double ag = asin(C.r/d);
    152         double base = Angle2(P-O);
    153         ans[0] = base + ag, ans[1] = base - ag;
    154         ans[0] = Change(ans[0]), ans[1] = Change(ans[1]);
    155         while(ans[0] >= 180.0)    ans[0] -= 180.0;
    156         while(ans[0] < 0)        ans[0] += 180.0;
    157         while(ans[1] >= 180.0)    ans[1] -= 180.0;
    158         while(ans[1] < 0)        ans[1] += 180.0;
    159         if(ans[0] >= ans[1])    swap(ans[0], ans[1]);
    160         printf("[%.6lf,%.6lf]
    ", ans[0], ans[1]);
    161     }
    162 }
    163 
    164 vector<Point> sol;
    165 struct Line
    166 {
    167     Point p;
    168     Vector v;
    169     Line()    { }
    170     Line(Point p, Vector v): p(p), v(v)    {}
    171     Point point(double t)
    172     {
    173         return p + v*t;
    174     }
    175     Line move(double d)
    176     {
    177         return Line(p + Normal(v)*d, v);
    178     }
    179 };
    180 Point GetIntersection(Line a, Line b)
    181 {
    182     Vector u = a.p - b.p;
    183     double t = Cross(b.v, u) / Cross(a.v, b.v);
    184     return a.p + a.v*t;
    185 }
    186 struct Circle2
    187 {
    188     Point c;    //圆心
    189     double r;    //半径
    190     Point point(double a)
    191     {
    192         return Point(c.x+r*cos(a), c.y+r*sin(a));
    193     }
    194 };
    195 //两圆相交并返回交点个数 
    196 int getLineCircleIntersection(Line L, Circle2 C, vector<Point>& sol)
    197 {
    198     double t1, t2;
    199     double a = L.v.x, b = L.p.x - C.c.x, c = L.v.y, d = L.p.y - C.c.y;
    200     double e = a*a + c*c, f = 2*(a*b + c*d), g = b*b + d*d - C.r*C.r;
    201     double delta = f*f - 4*e*g;        //判别式
    202     if(dcmp(delta) < 0)    return 0;    //相离
    203     if(dcmp(delta) == 0)            //相切
    204     {
    205         t1 = t2 = -f / (2 * e);
    206         sol.push_back(L.point(t1));
    207         return 1;
    208     }
    209     //相交
    210     t1 = (-f - sqrt(delta)) / (2 * e);    sol.push_back(L.point(t1));
    211     t2 = (-f + sqrt(delta)) / (2 * e);    sol.push_back(L.point(t2));
    212     return 2;
    213 }
    214 void problem3()
    215 {
    216     Circle2 C;
    217     Point A, B;
    218     scanf("%lf%lf%lf%lf%lf%lf%lf", &C.c.x, &C.c.y, &A.x, &A.y, &B.x, &B.y, &C.r);
    219     Vector v = (A-B)/Length(A-B)*C.r;
    220     //printf("%lf
    ", Length(v));
    221     Point p1 = A + Point(-v.y, v.x);
    222     Point p2 = A + Point(v.y, -v.x);
    223     //printf("%lf
    %lf", Length(p1-C.c), Length(p2-C.c));
    224     Line L1(p1, v), L2(p2, v);
    225     
    226     sol.clear();
    227     int cnt =  getLineCircleIntersection(L1, C, sol);
    228     cnt += getLineCircleIntersection(L2, C, sol);
    229     sort(sol.begin(), sol.end());
    230     if(cnt == 0)    { printf("[]
    "); return; }
    231     printf("[");
    232     for(int i = 0; i < cnt-1; ++i)    printf("(%.6lf,%.6lf),", sol[i].x, sol[i].y);
    233     printf("(%.6lf,%.6lf)]
    ", sol[cnt-1].x, sol[cnt-1].y);
    234 }
    235 
    236 void problem4()
    237 {
    238     double r;
    239     Point A, B, C, D, E, ans[4];
    240     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);
    241     Line a(A, B-A), b(C, D-C);
    242     Line L1 = a.move(r), L2 = a.move(-r);
    243     Line L3 = b.move(r), L4 = b.move(-r);
    244     ans[0] = GetIntersection(L1, L3);
    245     ans[1] = GetIntersection(L1, L4);
    246     ans[2] = GetIntersection(L2, L3);
    247     ans[3] = GetIntersection(L2, L4);
    248     sort(ans, ans+4);
    249     printf("[");
    250     for(int i = 0; i < 3; ++i)    printf("(%.6lf,%.6lf),", ans[i].x, ans[i].y);
    251     printf("(%.6lf,%.6lf)]
    ", ans[3].x, ans[3].y);
    252 }
    253 
    254 int getCircleCircleIntersection(Circle2 C1, Circle2 C2, vector<Point>& sol)
    255 {
    256     double d = Length(C1.c - C2.c);
    257     if(dcmp(d) == 0)
    258     {
    259         if(dcmp(C1.r - C2.r) == 0)    return -1;
    260         return 0;
    261     }
    262     if(dcmp(C1.r + C2.r - d) < 0)    return 0;
    263     if(dcmp(fabs(C1.r - C2.r) - d) > 0)    return 0;
    264 
    265     double a = Angle2(C2.c - C1.c);
    266     double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d));
    267     Point p1 = C1.point(a+da), p2 = C1.point(a-da);
    268     sol.push_back(p1);
    269     if(p1 == p2)    return 1;
    270     sol.push_back(p2);
    271     return 2;
    272 }
    273 
    274 void problem5()
    275 {
    276     Circle2 C1, C2;
    277     double r;
    278     vector<Point> sol;
    279     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);
    280     double d = Length(C1.c - C2.c);
    281     C1.r += r, C2.r += r;
    282     if(dcmp(C1.r+C2.r-d) < 0)    { printf("[]
    "); return; }
    283     int n = getCircleCircleIntersection(C1, C2, sol);
    284     sort(sol.begin(), sol.end());
    285     printf("[");
    286     for(int i = 0; i < n-1; ++i)    printf("(%.6lf,%.6lf),", sol[i].x, sol[i].y);
    287     printf("(%.6lf,%.6lf)]
    ", sol[n-1].x, sol[n-1].y);
    288 }
    289 
    290 int main()
    291 {
    292     #ifdef    LOCAL
    293         freopen("12304in.txt", "r", stdin);
    294     #endif
    295 
    296     while(scanf("%s", s) == 1)
    297     {
    298         int proID = ID(s);
    299         switch(proID)
    300         {
    301             case 0:    problem0();    break;
    302             case 1:    problem1();    break;
    303             case 2:    problem2();    break;
    304             case 3:    problem3();    break;
    305             case 4:    problem4();    break;
    306             case 5:    problem5();    break;
    307             default: break;
    308         }
    309     }
    310     
    311     return 0;
    312 }
    代码君
  • 相关阅读:
    剑指offer:面试题25、二叉树中和为某值的路径
    剑指offer:面试题24、二叉搜索树的后续遍历序列
    剑指offer:面试题23、从上往下打印二叉树
    剑指offer:面试题22、栈的压入、弹出序列
    剑指offer:面试题21、包含min函数的栈
    剑指offer:面试题20、顺时针打印矩阵
    剑指offer:面试题19、二叉树的镜像
    剑指offer:面试题18、树的子结构
    剑指offer:面试题17、合并两个排序的链表
    剑指offer:面试题16、反转链表
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4032240.html
Copyright © 2011-2022 走看看