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 ? -11;
}
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);
            }
        }
    }
}

posted on 2011-10-17 12:15 BUPT-[aswmtjdsj] @ Penalty 阅读(520) 评论(0)  编辑 收藏 引用 所属分类: 计算几何UVA Solution Report


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2011年9月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

导航

统计

常用链接

留言簿(1)

随笔分类(150)

随笔档案(71)

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜