UVA 12304 2D Geometry 110 in 1! 【几何基础知识题】【敲个两三百行也没啥是吧?咱们都是纯爷们儿】

UVA 12304 2D Geometry 110 in 1! 【几何基础知识题】【敲个两三百行也没啥是吧?咱们都是纯爷们儿】

这题是RujiaLiu的几何专场中,第四简单的题目了。
果断无脑流,果断需要敲无数行模板,果断需要考虑各种情况。
还好srgba给的sample照顾到了所有情况,并且没有太卡精度,不过没有spj,不得不说老uva在这一点上太二了。

题目六部分,六个和圆有关的问题。以及附上我的模板:
预备知识(模板):
eps
sgn符号函数
点(向量)类:
构造、加、减、数乘(放缩)、点积、叉积、比较器、反向、法向、单位向量、向量以任意角度旋转。
直线类:
构造、旋转、平移、判点其上、算点距离、点投影、点对称(后加的,无关)、求交点。
圆类:
两点构造、三点构造(外接圆)、点半径构造、点在内or上or外、求点到圆的切线。
六个问题:

三角形外接圆:
根据垂径定理搞定,两线求交(不是自己写的),精度比较高的方法是叉积算比例求定比分点什么的。

三角形内切圆:
抄的别人的模板。(我觉得这个最难,虽然我自己也写了一个吧,后来删掉了,因为丢精度比较厉害。就是用那种算夹角,旋转向量再求交的方法)

给定一点一圆,求过该点的圆切线:
两种情况(第三种是圆内点,无解):一,点在圆上,直接求出点到圆心的矢量的法向量,就是所求;二,点在圆外,求出点心矢量后,根据切线三角形,算出旋转角,向量对称旋转即得。

给定一点一线和半径求圆:
四种情况:一,圆直径小于点线距离,无解;二,等于,唯一解,求出点在直线投影,两点连线中点即为圆心;三,圆直径大于点线距离,做个梯形,算一下夹角,对称旋转即可出两解;四,点在线上,点平移即可。

两条线加半径定圆:
因为线不平行,所以一定有解,且是四个解:即把每条线向两个方向平移半径长度即可确定2*2个圆。

两个圆加半径确定圆:
三种情况:两圆距离(圆心距离减半径和)大于新圆直径,无解:等于,唯一解,圆外线段中点,不好求,那么就是两圆连线上(ra+r)/(ra+rb+2*r)出的分点;小于,两解,构造三角形,算出定比分点比例,垂直平移分点即可。

上海比赛的时候模板确实用上了- -不过还是没出题。太悲剧了。自己还是太弱了啊- -。

附上我的2D几何模板吧~略长~387lines

/*
   point class && line class && circle class 
   Many things about circle and so on
   WTF
 
*/
#include 
< iostream >
#include 
< cstdio >
#include 
< algorithm >
#include 
< cstring >
#include 
< cmath >
using   namespace  std;
#define  maxn 1005
#define  sqr(x) ((x) * (x))
int  n;
const   double  eps  =  1e - 8 ;
const   double  pi  =  acos( - 1.0 );
int  sgn( double  x)
{
    
return  fabs(x)  <  eps  ?   0  : x  <   - eps  ?   - 1 1 ;
}
struct  point
{
    
double  x,y;
    point(){}
    point(
double  a, double  b):x(a),y(b){}
    point 
operator   -  (point p){ return  point(x  -  p.x,y  -  p.y);}
    point 
operator   +  (point p){ return  point(x  +  p.x,y  +  p.y);}
    
double  norm(){ return  sqrt(sqr(x)  +  sqr(y));}
    
double  norm2(){ return  sqr(x)  +  sqr(y);}
    
double   operator   *  (point p){ return  x  *  p.x  +  y  *  p.y;}
    point 
operator   *  ( double  a){ return  point(x  *  a,y  *  a);}
    
double   operator   ^  (point p){ return  x  *  p.y  -  y  *  p.x;}
    
bool   operator   ==  (point p){ return  sgn(x - p.x) == 0 && sgn(y - p.y) == 0 ;}
    
bool   operator   <  ( const  point  & p){ return  sgn(x  -  p.x)  <   0   ||  (sgn(x  -  p.x)  ==   0   &&  sgn(y  -  p.y)  <   0 );}
    point rev(){
return  point( - x, - y);}
    point ver(){
return  point(y, - x);}
    point unit(){
return  point(x  /  norm(),y  /  norm());}
    point rotate(
double  theta) // the rotate function for vector to rotate
    { // in counter-clockwise direction
         return  point(x * cos(theta) - y * sin(theta),x * sin(theta) + y * cos(theta));
    }
}p[maxn];
struct  line
{
    point p,k;
    line(){}
    
// MIND THIS!!!!!
    line(point a,point b):p(a),k(b){} // a is the fixed point,k is the directed vector
    line rotate( double  theta){line l;l.p = p;l.k = k.rotate(theta); return  l;}
    
bool  on(point q){ return  sgn((q - p)  ^  k)  ==   0 ;}
    
// move the line acording to the parpendicular-direction with offset distance
    line move( double  offset) // to which direction??
    { // every time we use this,we can try the bi-direction
        point vec  =  k.ver();
        vec 
=  vec.unit()  *  offset;
        point q 
=  p  +  vec;
        
return  line(q,k);
    }
    
// distance from a point to a line
     double  dis(point q)
    {
        point a 
=  p,b  =  a  +  k;
        
return  fabs((a  -  q)  ^  (b  -  q))  /  k.norm();
    }
    
// cast the point to the line and find the pedal
     /*
       by construct the line through the 'q' parallel to the origin line
       calc the lq.p 's vector to 'q'
       add it onto the origin line's p
     
*/
    point cast(point q)
// something wrong
    {
        
double  d  =  line(p,k).dis(q);
        line lq 
=  line(p,k).move(d);
        point vec;
        
if ( ! lq.on(q))
            lq 
=  line(p,k).move( - d);
        vec 
=  q  -  lq.p;
        
return  p  +  vec;
    }
    
// calc the symmetrical point of the given one againt the given line
    point sym(point q)
    {
        point c 
=  line(p,k).cast(q);
        point vec 
=  c  -  q;
        
return  c  +  vec;
    }
    
// copied from some big cow
    
// by vector product and "division point"
     int  cross(line q,point  & ans)
    {
        point a 
=  p,b  =  p  +  k,c  =  q.p,d  =  q.p  +  q.k;
        ans 
=  d;
        
double  rate  =  ((b - a) ^ (a - d))  /  ((b - a) ^ (c - d));
        ans 
=  ans  +  ((c  -  d)  *  rate);
    }
};
struct  circle
{
    point o;
    
double  r;
    circle(){}
    circle(point _o,
double  _r):o(_o),r(_r){}
    
// by two points to calc the minimum circle
    circle(point a,point b)
    {
        o 
=  (a  +  b)  *   0.5 ;
        r 
=  (a  -  o).norm();
    }
    
// give three points (not on the same line)to calc the decided circle
    circle(point a,point b,point c)
    {
        point m1 
=  (a  +  b)  *   0.5 ,m2  =  (b  +  c)  *   0.5 ;
        line l1 
=  line(m1,(b - a).ver()),l2  =  line(m2,(c - b).ver());
        l1.cross(l2,o);
        r 
=  (a - o).norm();
    }
    
// judge a point in or on the circle or not
     bool   in (point x)
    {
        
return  sgn((x  -  o).norm()  -  r)  <=   0 ;
    }
    
// judge a point on the circular of the circle or not
     bool  inandon(point x)
    {
        
return  sgn((x  -  o).norm()  -  r)  ==   0 ;
    }
    
// give a point and a cirlce,calc the two tangent line (just angles)
    
// by rotation ::mode 1
    
// if the point p is on the circular of the circle
    
// just output one tangentline ::mode 2
     void  tangentline(point p, double   & th1, double   & th2, int  mode)
    {
        
double  alpha  =  atan2(o.y  -  p.y,o.x  -  p.x);
        
if (mode  ==   1 )
        {
            th1 
=  alpha  +  pi  *   0.5 ;
            
if (sgn(th1  -  pi)  >=   0 )
                th1 
-=  pi;
            
else   if (sgn(th1)  <   0 )
                th1 
+=  pi;
            th1 
=  th1  /  pi  *   180.0 ;
        }
        
else
        {
            
// circle center and point p 's connected line 's angle
             double  theta  =  asin(r  /  (p  -  o).norm());
            th1 
=  alpha  +  theta;
            
while (sgn(th1  -  pi)  >=   0 )
                th1 
-=  pi;
            
while (sgn(th1)  <   0 )
                th1 
+=  pi;
            th2 
=  alpha  -  theta;
            
while (sgn(th2  -  pi)  >=   0 )
                th2 
-=  pi;
            
while (sgn(th2)  <   0 )
                th2 
+=  pi;
            th1 
=  th1  /  pi  *   180.0 ;
            th2 
=  th2  /  pi  *   180.0 ;
        }
    }
};
// copied from some big cow
// to calculate the insribed circle of a triangle
circle inscribed(point a,point b,point c)
{
    point a1 
=  a  +  (b - a).unit()  +  (c  -  a).unit(),b1  =  b  +  (a - b).unit() + (c - b).unit();
    point ans;
    line(a,a1
- a).cross(line(b,b1 - b),ans);
    
double  r  =  line(a,b - a).dis(ans);
    
return  circle(ans,r);
}
int  onelineonepoint(point p,line l, double  r,circle  & a,circle  & b)
{
    
double  d  =  l.dis(p);
    
if (sgn(d  -   2.0   *  r)  >   0 )
        
return   0 ;
    
else   if (sgn(d  -   2.0   *  r)  ==   0 )
    {
        point c 
=  l.cast(p);
        a 
=  circle((c  +  p)  *   0.5 ,r);
        
return   1 ;
    }
    
else   if (sgn(d  -   2.0   *  r)  <   0   &&  sgn(d)  >   0 )
    {
        
double  det,theta;
        det 
=  d  -  r;
        theta 
=  acos(det  /  r);
        point c 
=  l.cast(p);
        point to 
=  c  -  p;
        to 
=  to.unit()  *  r;
        point vec1 
=  to.rotate(theta),vec2  =  to.rotate( - theta);
        a 
=  circle(p  +  vec1,r);
        b 
=  circle(p  +  vec2,r);
        
return   2 ;
    }
    
else   if (sgn(d)  ==   0 ) // the point is on the line
    {
        point per 
=  l.k.ver();
        per 
=  per.unit()  *  r;
        a 
=  circle(p  +  per,r);
        b 
=  circle(p  +  per.rev(),r);
        
return   2 ;
    }
}
// use two cross lines and one radius to calc four circles
// circle - answer array
circle four[ 10 ];
// use the center of circle to compare circles
bool  cmpcircle(circle a,circle b)
{
    
return  a.o  <  b.o;
}
void  twolineoneradius(line a,line b, double  r)
{
    line A[
2 ],B[ 2 ];
    A[
0 =  a.move(r),A[ 1 =  a.move( - r);
    B[
0 =  b.move(r),B[ 1 =  b.move( - r);
    
int  cnt  =   1 ;
    
for ( int  i  =   0 ;i  <   2 ;i ++ )
        
for ( int  j  =   0 ;j  <   2 ;j ++ )
        {
            point temp;
            A[i].cross(B[j],temp);
            four[cnt
++ =  circle(temp,r);
        }
}
// use two disjoint circle to calc one or two new circles tangent to them with given 'r'
// not in the middle line !!!!
int  twocircle(circle a,circle b, double  r,circle  & c,circle  & d)
{
    point dir 
=  (b.o  -  a.o);
    
double  dis  =  dir.norm();
    
double  len  =  dis  -  a.r  -  b.r;
    
double  ra  =  r  +  a.r,rb  =  r  +  b.r;
    
if (sgn(len  -   2.0   *  r)  >   0 )
        
return   0 ;
    
else   if (sgn(len  -   2.0   *  r)  ==   0 )
    {
        point to 
=  dir  *  (ra  /  (ra  +  rb));
        c 
=  circle(a.o  +  to,r);
        
return   1 ;
    }
    
else
    {
        
// r1^2 - l1^2 = r2^2 - l2^2
        
// l1 + l2 = l
        
// wtf
         double  tempto  =  (sqr(ra)  -  sqr(rb)  +  sqr(dis))  /  ( 2.0   *  dis);
        point to 
=  dir  *  (tempto  /  dis);
        point temp 
=  (a.o  +  to);
        point per 
=  to.ver();
        
double  rate  =  sqrt(sqr(ra)  -  to.norm2()) /  per.norm();
        per 
=  per  *  rate;
        point per2 
=  per.rev();
        c 
=  circle(temp  +  per,r);
        d 
=  circle(temp  +  per2,r);
        
return   2 ;
    }
}
// we judge three points on the same line or not
bool  oneline(point a,point b,point c){ return  sgn((a  -  b)  ^  (a  -  c))  ==   0 ;}
char  opt[ 1000 ];
char  type[][ 1000 =  { " CircumscribedCircle " , " InscribedCircle " , " TangentLineThroughPoint " , " CircleThroughAPointAndTangentToALineWithRadius " , " CircleTangentToTwoLinesWithRadius " , " CircleTangentToTwoDisjointCirclesWithRadius " };
int  main()
{
    
while (scanf( " %s " ,opt)  ==   1 )
    {
        
int  mark  =   - 1 ;
        
for ( int  i  =   0 ;i  <   6 ;i ++ )
        {
            
if (strcmp(opt,type[i])  ==   0 )
            {
                mark 
=  i;
                
break ;
            }
        }
        
if (mark  ==   0 )
        {
            
for ( int  i  =   0 ;i  <   3 ;i ++ )
            {
                
double  x,y;
                scanf(
" %lf %lf " , & x, & y);
                p[i] 
=  point(x,y);
            }
            circle ans 
=  circle(p[ 0 ],p[ 1 ],p[ 2 ]);
            printf(
" (%.6lf,%.6lf,%.6lf)\n " ,ans.o.x + 1e - 10 ,ans.o.y + 1e - 10 ,ans.r + 1e - 10 );
        }
        
else   if (mark  ==   1 )
        {
            
for ( int  i  =   0 ;i  <   3 ;i ++ )
            {
                
double  x,y;
                scanf(
" %lf %lf " , & x, & y);
                p[i] 
=  point(x,y);
            }
            circle ans 
=  inscribed(p[ 0 ],p[ 1 ],p[ 2 ]);
            printf(
" (%.6lf,%.6lf,%.6lf)\n " ,ans.o.x + 1e - 10 ,ans.o.y + 1e - 10 ,ans.r + 1e - 10 );
        }
        
else   if (mark  ==   2 )
        {
            
double  x,y,r;
            scanf(
" %lf %lf %lf " , & x, & y, & r);
            circle o 
=  circle(point(x,y),r);
            scanf(
" %lf %lf " , & x, & y);
            
double  t1,t2;
            point p 
=  point(x,y);
            
if (o. in (p))
            {
                
if (o.inandon(p))
                {
                    o.tangentline(p,t1,t2,
1 );
                    printf(
" [%.6lf]\n " ,t1 + 1e - 10 );
                }
                
else
                    puts(
" [] " );
            }
            
else
            {
                o.tangentline(p,t1,t2,
2 );
                
if (sgn(t1  -  t2)  >   0 )
                    swap(t1,t2);
                printf(
" [%.6lf,%.6lf]\n " ,t1 + 1e - 10 ,t2 + 1e - 10 );
            }
        }
        
else   if (mark  ==   3 )
        {
            
double  x,y;
            
for ( int  i  =   0 ;i  <   3 ;i ++ )
            {
                scanf(
" %lf %lf " , & x, & y);
                p[i] 
=  point(x,y);
            }
            
double  r;
            scanf(
" %lf " , & r);
            circle a,b;
            
int  mod  =  onelineonepoint(p[ 0 ],line(p[ 1 ],p[ 2 ] - p[ 1 ]),r,a,b);
            
if (mod  ==   0 )
                puts(
" [] " );
            
else   if (mod  ==   1 )
                printf(
" [(%.6lf,%.6lf)]\n " ,a.o.x + 1e - 10 ,a.o.y + 1e - 10 );
            
else
            {
                
if (b.o  <  a.o)
                    swap(a,b);
                printf(
" [(%.6lf,%.6lf),(%.6lf,%.6lf)]\n " ,a.o.x + 1e - 10 ,a.o.y + 1e - 10 ,b.o.x + 1e - 10 ,b.o.y + 1e - 10 );
            }
        }
        
else   if (mark  ==   4 )
        {
            
double  x,y,r;
            
for ( int  i  =   0 ;i  <   4 ;i ++ )
            {
                scanf(
" %lf %lf " , & x, & y);
                p[i] 
=  point(x,y);
            }
            scanf(
" %lf " , & r);
            twolineoneradius(line(p[
0 ],p[ 1 ] - p[ 0 ]),line(p[ 2 ],p[ 3 ] - p[ 2 ]),r);
            sort(four 
+   1 ,four  +   5 ,cmpcircle);
            putchar(
' [ ' );
            
for ( int  i  =   1 ;i  <=   4 ;i ++ )
                printf(
" (%.6lf,%.6lf)%c " ,four[i].o.x + 1e - 10 ,four[i].o.y + 1e - 10 ,i  ==   4 ? ' ] ' : ' , ' );
            puts(
"" );
        }
        
else   if (mark  ==   5 )
        {
            
double  x,y,r;
            scanf(
" %lf %lf %lf " , & x, & y, & r);
            circle a(point(x,y),r);
            scanf(
" %lf %lf %lf " , & x, & y, & r);
            circle b(point(x,y),r);
            scanf(
" %lf " , & r);
            circle c,d;
            
int  mod  =  twocircle(a,b,r,c,d);
            
if (mod  ==   0 )
                puts(
" [] " );
            
else   if (mod  ==   1 )
                printf(
" [(%.6lf,%.6lf)]\n " ,c.o.x + 1e - 10 ,c.o.y + 1e - 10 );
            
else
            {
                
if (d.o  <  c.o)
                    swap(c,d);
                printf(
" [(%.6lf,%.6lf),(%.6lf,%.6lf)]\n " ,c.o.x + 1e - 10 ,c.o.y + 1e - 10 ,d.o.x + 1e - 10 ,d.o.y + 1e - 10 );
            }
        }
    }
}
å

你可能感兴趣的:(UVA 12304 2D Geometry 110 in 1! 【几何基础知识题】【敲个两三百行也没啥是吧?咱们都是纯爷们儿】)