UVA 12304 2D Geometry 110 in 1! 六个直线与圆的问题+经典几何

来源:互联网 发布:cs1.5优化教程视频 编辑:程序博客网 时间:2024/04/30 13:32

六个直线与圆的问题+经典几何


题目要求:让你写六个函数,每个函数实现一个计算:


1,三角形外接圆


2,三角形内切圆


3,过定点和圆的切线,输出切线的极角


4,求过定点p,并且和直线相切的半径为r的圆


5,求半径为r的,并且和两条不平行直线相切的圆


6,给出两个相离的圆,求所有和这两个圆外切并且半径为r的圆



解题思路:


1,刘汝佳的白书上说的很透彻,一步一步的模拟就可以了。


2,把这题写完,对几何知识的学习非常有帮助。


3,还是看代码把,毕竟这题太长了,思路都在代码里面。


#include<bits/stdc++.h>using namespace std;char str[200] ;const double eps = 1e-6;///精度函数int dcmp(double x) {  if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;}const double PI = acos(-1);struct Point { ///点  double x, y;  Point(double x=0, double y=0):x(x),y(y) { }};typedef Point Vector;///向量struct Circle{///圆的定义    Point c;    double r ;    Circle(Point c,double r):c(c),r(r){}///构造函数    Point point(double a){///根据圆心角求圆上的坐标,返回一个点        return Point(c.x+cos(a)*r,c.y+sin(a)*r) ;    }};Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }Vector operator - (Point A, Point 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);}bool operator == (const Point& a, const Point &b) {return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;}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 Cross(Vector A,Vector B){return A.x*B.y - A.y*B.x ;}Vector Rotate(Vector A,double rad){return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));}double angle(Vector v){return atan2(v.y,v.x);}Vector Normal(Vector A) {  double L = Length(A);  return Vector(-A.y/L, A.x/L);}double lineAngleDegree(Vector v) {  double ang = angle(v)*180.0/PI;  while(dcmp(ang) < 0) ang += 360.0;  while(dcmp(ang-180) >= 0) ang -= 180.0;  return ang;}struct Line {///线的定义  Point p;  Vector v;  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);  }};double DistanceToLine(Point P,Point A,Point B){    Vector v1 = B-A ,v2 = P-A ;    return fabs(Cross(v1,v2))/Length(v1) ;}Point readpoint(){    double x,y ;    scanf("%lf%lf",&x,&y);    return Point(x,y) ;}Circle readcircle(){    double x,y,r ;    scanf("%lf%lf%lf",&x,&y,&r);    return Circle(Point(x,y),r) ;}///1,求三角形的外接圆Circle CircumscribedCircle(Point p1, Point p2, Point p3) {  double Bx = p2.x-p1.x, By = p2.y-p1.y;  double Cx = p3.x-p1.x, Cy = p3.y-p1.y;  double D = 2*(Bx*Cy-By*Cx);  double cx = (Cy*(Bx*Bx+By*By) - By*(Cx*Cx+Cy*Cy))/D + p1.x;  double cy = (Bx*(Cx*Cx+Cy*Cy) - Cx*(Bx*Bx+By*By))/D + p1.y;  Point p = Point(cx, cy);  return Circle(p, Length(p1-p));}///2,求三角形的内接圆Circle InscribedCircle(Point p1, Point p2, Point p3) {  double a = Length(p2-p3);  double b = Length(p3-p1);  double c = Length(p1-p2);  Point p = (p1*a+p2*b+p3*c)/(a+b+c);  return Circle(p, DistanceToLine(p, p1, p2));}///3,过点p到圆C的切线。v[i]是第i条切线的向量。返回切线条数int getTangents(Point p, Circle C, Vector* v) {  Vector u = C.c - p;  double dist = Length(u);  if(dist < C.r) return 0;  else if(dcmp(dist - C.r) == 0) { // p在圆上,只有一条切线    v[0] = Rotate(u, PI/2);    return 1;  } else {    double ang = asin(C.r / dist);    v[0] = Rotate(u, -ang);    v[1] = Rotate(u, +ang);    return 2;  }}///4,获得直线和圆的位置关系,sol没有清空,可以保存所有的直线与圆的交点。调用两次,求两条直线int getLineCircleIntersection(Line L,Circle C,double& t1,double& t2,vector<Point>& sol){    double a = L.v.x ;    double b = L.p.x - C.c.x;    double c = L.v.y;    double d = L.p.y - C.c.y;    double e = a*a+c*c ;    double f = 2*(a*b+c*d) ;    double g = b*b+d*d - C.r*C.r ;    double delta = f*f -4*e*g ;///判别式    if(dcmp(delta)<0) return 0 ;///相离    if(dcmp(delta)==0){ ///相切        t1 = t2 = -f / (2*e) ;        sol.push_back(L.point(t1)) ;        return 1 ;    }    t1 = (-f - sqrt(delta))/(2*e) ;    sol.push_back(L.point(t1)) ;    t2 = (-f + sqrt(delta))/(2*e) ;    sol.push_back(L.point(t2)) ;    return 2 ;}///5,固定半径的圆,同时与两条直线相交,获得两条直线的交点,注意v,w不共线,即有唯一交点Point GetLineIntersection(Point P,Vector v,Point Q,Vector w){    Vector u = P-Q ;    double t = Cross(w,u)/Cross(v,w) ;    return P+v*t ;}Point GetLineIntersection(Line a,Line b){    return GetLineIntersection(a.p,a.v,b.p,b.v) ;}///6,求两圆相交而已。int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point>& sol){    double d=Length(C1.c-C2.c);    if(dcmp(d)==0){        if(dcmp(C1.r-C2.r)==0)return -1;        return 0;    }    if(dcmp(C1.r+C2.r-d)<0)return 0;    if(dcmp(fabs(C1.r-C2.r)-d)>0)return 0;    double a=angle(C2.c-C1.c) ;    double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));    Point p1=C1.point(a-da);    Point p2=C1.point(a+da);    sol.push_back(p1);    if(p1==p2)return 1;    sol.push_back(p2) ;    return 2;}int main(){    while(~scanf("%s",str)){        if(strcmp(str,"CircumscribedCircle")==0){///中线的交点            Point p1 = readpoint() ;            Point p2 = readpoint() ;            Point p3 = readpoint() ;            Circle ans = CircumscribedCircle(p1,p2,p3) ;            printf("(%lf,%lf,%lf)\n",ans.c.x,ans.c.y,ans.r);        }        if(strcmp(str,"InscribedCircle")==0){///内切圆            Point p1 = readpoint() ;            Point p2 = readpoint() ;            Point p3 = readpoint() ;            Circle ans = InscribedCircle(p1,p2,p3) ;            printf("(%lf,%lf,%lf)\n",ans.c.x,ans.c.y,ans.r);        }        if(strcmp(str,"TangentLineThroughPoint")==0){///过点和圆相切的切线            Circle C = readcircle() ;            Point P = readpoint() ;            Vector ans[2];            int num = getTangents(P,C,ans) ;            vector<double> ans2;            for(int i=0;i<num;i++){                ans2.push_back(lineAngleDegree(ans[i]));            }            sort(ans2.begin(),ans2.end());            printf("[");            for(int i=0;i<num-1;i++){                printf("%lf,",ans2[i]);            }            if(num>=1)printf("%lf]\n",ans2[num-1]);            else printf("]\n");        }        if(strcmp(str,"CircleThroughAPointAndTangentToALineWithRadius")==0){            Point p = readpoint() ;            Point p1 = readpoint() ;            Point p2 = readpoint() ;            Line L = Line(p1,p1-p2) ;            double r ;            scanf("%lf",&r);            Circle C = Circle(p,r) ;            Line L1 = L.move(r) ;            Line L2 = L.move(-r) ;            vector<Point> ans;            ans.clear() ;            double t1 ;            double t2 ;            getLineCircleIntersection(L1,C,t1,t2,ans) ;            getLineCircleIntersection(L2,C,t1,t2,ans) ;            sort(ans.begin(),ans.end()) ;            printf("[");            for(int i=0;i<(int)(ans.size())-1;i++)printf("(%lf,%lf),",ans[i].x,ans[i].y);            if((int)(ans.size())-1>=0)printf("(%lf,%lf)]\n",ans[ans.size()-1].x,ans[ans.size()-1].y);            else printf("]\n");        }        if(strcmp(str,"CircleTangentToTwoLinesWithRadius")==0){            Point p1=readpoint() ;            Point p2=readpoint() ;            Point p3=readpoint() ;            Point p4=readpoint() ;            double r ;            scanf("%lf",&r);            Line L1=Line(p1,p1-p2) ;            Line L2=Line(p3,p3-p4) ;            Line L1a = L1.move(r) ;            Line L1b = L1.move(-r) ;            Line L2a = L2.move(r) ;            Line L2b = L2.move(-r) ;            vector<Point> ans ;            ans.clear() ;            ans.push_back(GetLineIntersection(L1a,L2a)) ;            ans.push_back(GetLineIntersection(L1a,L2b)) ;            ans.push_back(GetLineIntersection(L1b,L2a)) ;            ans.push_back(GetLineIntersection(L1b,L2b)) ;            sort(ans.begin(),ans.end()) ;            printf("[");            for(int i=0;i<3;i++)printf("(%lf,%lf),",ans[i].x,ans[i].y);            printf("(%lf,%lf)]\n",ans[3].x,ans[3].y);        }        if(strcmp(str,"CircleTangentToTwoDisjointCirclesWithRadius")==0){            Circle c1 = readcircle();            Circle c2 = readcircle();            double r ;            scanf("%lf",&r);            c1.r+=r ;            c2.r+=r ;            vector<Point> ans ;            ans.clear() ;            getCircleCircleIntersection(c1,c2,ans);            sort(ans.begin(),ans.end()) ;            printf("[");            for(int i=0;i<(int)(ans.size())-1;i++){                printf("(%lf,%lf),",ans[i].x,ans[i].y);            }            if((int)(ans.size())-1>=0)printf("(%lf,%lf)]\n",ans[ans.size()-1].x,ans[ans.size()-1].y);            else printf("]\n");        }    }}/**inputCircumscribedCircle 0 0 20 1 8 17InscribedCircle 0 0 20 1 8 17TangentLineThroughPoint 200 200 100 40 150TangentLineThroughPoint 200 200 100 200 100TangentLineThroughPoint 200 200 100 270 210CircleThroughAPointAndTangentToALineWithRadius 100 200 75 190 185 65 100CircleThroughAPointAndTangentToALineWithRadius 75 190 75 190 185 65 100CircleThroughAPointAndTangentToALineWithRadius 100 300 100 100 200 100 100CircleThroughAPointAndTangentToALineWithRadius 100 300 100 100 200 100 99CircleTangentToTwoLinesWithRadius 50 80 320 190 85 190 125 40 30CircleTangentToTwoDisjointCirclesWithRadius 120 200 50 210 150 30 25CircleTangentToTwoDisjointCirclesWithRadius 100 100 80 300 250 70 50*/

附上大白上的汝佳的代码:

// UVa12304 2D Geometry 110 in 1!// Rujia Liu#include<cstdio>#include<cmath>#include<algorithm>#include<string>#include<iostream>#include<vector>#include<cassert>using namespace std;const double eps = 1e-6;int dcmp(double x) {  if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;}const double PI = acos(-1);struct Point {  double x, y;  Point(double x=0, double y=0):x(x),y(y) { }};typedef Point Vector;Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }Vector operator - (Point A, Point 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);}bool operator == (const Point& a, const Point &b) {  return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;}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 Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }Vector Rotate(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);}Point GetLineIntersection(Point P, Point v, Point Q, Point w) {  Vector u = P-Q;  double t = Cross(w, u) / Cross(v, w);  return P+v*t;}Point GetLineProjection(Point P, Point A, Point B) {  Vector v = B-A;  return A+v*(Dot(v, P-A) / Dot(v, v));}double DistanceToLine(Point P, Point A, Point B) {  Vector v1 = B - A, v2 = P - A;  return fabs(Cross(v1, v2)) / Length(v1); // 如果不取绝对值,得到的是有向距离}struct Line {  Point p;  Vector v;  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);  }};struct Circle {  Point c;  double r;  Circle(Point c, double r):c(c),r(r) {}  Point point(double a) {    return Point(c.x + cos(a)*r, c.y + sin(a)*r);    }};Point GetLineIntersection(Line a, Line b) {  return GetLineIntersection(a.p, a.v, b.p, b.v);}double angle(Vector v) {  return atan2(v.y, v.x);}int getLineCircleIntersection(Line L, Circle C, double& t1, double& t2, vector<Point>& sol){  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 = 2*(a*b + c*d), g = b*b + d*d - C.r*C.r;  double delta = f*f - 4*e*g; // 判别式  if(dcmp(delta) < 0) return 0; // 相离  if(dcmp(delta) == 0) { // 相切    t1 = t2 = -f / (2 * e); sol.push_back(L.point(t1));    return 1;  }  // 相交  t1 = (-f - sqrt(delta)) / (2 * e); sol.push_back(L.point(t1));  t2 = (-f + sqrt(delta)) / (2 * e); sol.push_back(L.point(t2));  return 2;}int getCircleCircleIntersection(Circle C1, Circle C2, vector<Point>& sol) {  double d = Length(C1.c - C2.c);  if(dcmp(d) == 0) {    if(dcmp(C1.r - C2.r) == 0) return -1; // 重合,无穷多交点    return 0;  }  if(dcmp(C1.r + C2.r - d) < 0) return 0;  if(dcmp(fabs(C1.r-C2.r) - d) > 0) return 0;  double a = angle(C2.c - C1.c);  double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d));  Point p1 = C1.point(a-da), p2 = C1.point(a+da);  sol.push_back(p1);  if(p1 == p2) return 1;  sol.push_back(p2);  return 2;}/******************* Problem 1 **********************/Circle CircumscribedCircle(Point p1, Point p2, Point p3) {  double Bx = p2.x-p1.x, By = p2.y-p1.y;  double Cx = p3.x-p1.x, Cy = p3.y-p1.y;  double D = 2*(Bx*Cy-By*Cx);  double cx = (Cy*(Bx*Bx+By*By) - By*(Cx*Cx+Cy*Cy))/D + p1.x;  double cy = (Bx*(Cx*Cx+Cy*Cy) - Cx*(Bx*Bx+By*By))/D + p1.y;  Point p = Point(cx, cy);  return Circle(p, Length(p1-p));}/******************* Problem 2 **********************/Circle InscribedCircle(Point p1, Point p2, Point p3) {  double a = Length(p2-p3);  double b = Length(p3-p1);  double c = Length(p1-p2);  Point p = (p1*a+p2*b+p3*c)/(a+b+c);  return Circle(p, DistanceToLine(p, p1, p2));}/******************* Problem 3 **********************/// 过点p到圆C的切线。v[i]是第i条切线的向量。返回切线条数int getTangents(Point p, Circle C, Vector* v) {  Vector u = C.c - p;  double dist = Length(u);  if(dist < C.r) return 0;  else if(dcmp(dist - C.r) == 0) { // p在圆上,只有一条切线    v[0] = Rotate(u, PI/2);    return 1;  } else {    double ang = asin(C.r / dist);    v[0] = Rotate(u, -ang);    v[1] = Rotate(u, +ang);    return 2;  }}/******************* Problem 4 **********************/vector<Point> CircleThroughPointTangentToLineGivenRadius(Point p, Line L, double r) {  vector<Point> ans;  double t1, t2;  getLineCircleIntersection(L.move(-r), Circle(p, r), t1, t2, ans);  getLineCircleIntersection(L.move(r), Circle(p, r), t1, t2, ans);  return ans;}/******************* Problem 5 **********************/vector<Point> CircleTangentToLinesGivenRadius(Line a, Line b, double r) {  vector<Point> ans;  Line L1 = a.move(-r), L2 = a.move(r);  Line L3 = b.move(-r), L4 = b.move(r);  ans.push_back(GetLineIntersection(L1, L3));  ans.push_back(GetLineIntersection(L1, L4));  ans.push_back(GetLineIntersection(L2, L3));  ans.push_back(GetLineIntersection(L2, L4));  return ans;}/******************* Problem 6 **********************/vector<Point> CircleTangentToTwoDisjointCirclesWithRadius(Circle c1, Circle c2, double r) {  vector<Point> ans;  Vector v = c2.c - c1.c;  double dist = Length(v);  int d = dcmp(dist - c1.r -c2.r - r*2);  if(d > 0) return ans;  getCircleCircleIntersection(Circle(c1.c, c1.r+r), Circle(c2.c, c2.r+r), ans);  return ans;}// formattingdouble lineAngleDegree(Vector v) {  double ang = angle(v)*180.0/PI;  while(dcmp(ang) < 0) ang += 360.0;  while(dcmp(ang-180) >= 0) ang -= 180.0;  return ang;}void format(Circle c) {  printf("(%.6lf,%.6lf,%.6lf)\n", c.c.x, c.c.y, c.r);}void format(const vector<double>& ans) {  int n = ans.size();  sort(ans.begin(), ans.end());  printf("[");  if(n) {    printf("%.6lf", ans[0]);    for(int i = 1; i < n; i++) printf(",%.6lf", ans[i]);  }  printf("]\n");}void format(const vector<Point>& ans) {  int n = ans.size();  sort(ans.begin(), ans.end());  printf("[");  if(n) {    printf("(%.6lf,%.6lf)", ans[0].x, ans[0].y);    for(int i = 1; i < n; i++) printf(",(%.6lf,%.6lf)", ans[i].x, ans[i].y);  }  printf("]\n");}Line getLine(double x1, double y1, double x2, double y2) {  Point p1(x1,y1);  Point p2(x2,y2);  return Line(p1, p2-p1);}int main() {  string cmd;  while(cin >> cmd) {    double x1, y1, x2, y2, x3, y3, x4, y4, xp, yp, xc, yc, r1, r2, r;    if(cmd == "CircumscribedCircle") {      cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;      format(CircumscribedCircle(Point(x1,y1), Point(x2,y2), Point(x3,y3)));    }    if(cmd == "InscribedCircle") {      cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;      format(InscribedCircle(Point(x1,y1), Point(x2,y2), Point(x3,y3)));    }    if(cmd == "TangentLineThroughPoint") {      cin >> xc >> yc >> r >> xp >> yp;      Vector v[2];      vector<double> ans;      int cnt = getTangents(Point(xp, yp), Circle(Point(xc, yc), r), v);      for(int i = 0; i < cnt; i++) ans.push_back(lineAngleDegree(v[i]));      format(ans);    }    if(cmd == "CircleThroughAPointAndTangentToALineWithRadius") {      cin >> xp >> yp >> x1 >> y1 >> x2 >> y2 >> r;      format(CircleThroughPointTangentToLineGivenRadius(Point(xp, yp), getLine(x1, y1, x2, y2), r));    }    if(cmd == "CircleTangentToTwoLinesWithRadius") {      cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4 >> r;      format(CircleTangentToLinesGivenRadius(getLine(x1, y1, x2, y2), getLine(x3, y3, x4, y4), r));    }    if(cmd == "CircleTangentToTwoDisjointCirclesWithRadius") {      cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2 >> r;      format(CircleTangentToTwoDisjointCirclesWithRadius(Circle(Point(x1, y1), r1), Circle(Point(x2, y2), r2), r));    }  }  return 0;}


0 0