虽然这道题是个简单题,但对于我这样的弱渣还是研究了好久,而且自己根据大白书写的代码始终不对,无奈最后还是抄袭大神代码,
通过这个题得到下面几条心得,
1.做计算几何一定要注意精度问题,很难有绝对的相等,主要相对精度而言
2.做计算几何比较繁琐,一定要理清思路,代码思路一定要清晰
由于感觉大神的代码思路清晰,而且代码风格比较好,特贴出大神代码
,以及我自己按照大白书写的始终WA的代码,留着没事思考人生:
大神代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<string>
using namespace std;
const double eps=1e-6;
const double pi=acos(-1.0);
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
return x>eps?1:-1;
}
struct point
{
double x,y;
point(){}
point(double x,double y):x(x),y(y){}
point operator + (const point &t) const
{
return point(x+t.x,y+t.y);
}
point operator - (const point &t) const
{
return point(x-t.x,y-t.y);
}
point operator * (const double &t) const
{
return point(x*t,y*t);
}
point operator / (const double &t) const
{
return point(x/t,y/t);
}
bool operator < (const point &t) const
{
return x+eps<t.x||(!dcmp(x-t.x)&&y<t.y);
}
double len()
{
return sqrt(x*x+y*y);
}
double len2()
{
return x*x+y*y;
}
point normal()
{
return point(-y,x)/len();
}
void in()
{
cin>>x>>y;
}
void out()
{
printf("(%.6f,%.6f)",x,y);
}
};
double dis(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
point rotate(point a,double ct)
{
return point(a.x*cos(ct)-a.y*sin(ct),a.y*cos(ct)+a.x*sin(ct));
}
double cross(point a,point b)
{
return a.x*b.y-a.y*b.x;
}
double dot(point a,point b)
{
return a.x*b.x+a.y*b.y;
}
double fix(double x)
{
if(x<-eps) x+=pi;
return x*180./pi;
}
double angle(point v)
{
return atan2(v.y,v.x);
}
double disPointToLine(point a,point l,point r)
{
return fabs(cross(a-l,r-l))/dis(l,r);
}
struct Line
{
point a,v;
void in()
{
a.in();
v.in();
v=v-a;
}
Line(){}
Line(point a,point v):a(a),v(v){}
};
void lineLineIntersect(Line l,Line r,vector<point> &sol)
{
double t=cross((r.a-l.a),r.v)/cross(l.v,r.v);
sol.push_back(l.a+l.v*t);
}
struct Circle
{
point o;
double r;
void in()
{
o.in();
cin>>r;
}
point getpoint(double ct)
{
return point(r*cos(ct),r*sin(ct))+o;
}
void out()
{
printf("(%.6f,%.6f,%.6f)\n",o.x,o.y,r);
}
Circle(point o,double r):o(o),r(r){}
Circle(){}
};
void cirLineIntersect(Circle C,Line L,vector <point> &sol)
{
double e=L.v.len2(),f=dot(L.a-C.o,L.v)*2,g=(L.a-C.o).len2()-C.r*C.r;
double dlt=f*f-4*e*g;
if(dlt<-eps) return;
if(dlt<eps)
{
double t=-f/(2*e);
sol.push_back(L.v*t+L.a);
return ;
}
dlt=sqrt(dlt);
double t1=(-f+dlt)/(2*e),t2=(-f-dlt)/(2*e);
sol.push_back(L.v*t1+L.a);
sol.push_back(L.v*t2+L.a);
}
void cirCirIntersect(Circle C1,Circle C2, vector <point> &sol)
{
point v=C2.o-C1.o;
double d=v.len();
if(dcmp(d-C1.r-C2.r)>0) return;
double ct=angle(v),alf=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
sol.push_back(C1.getpoint(ct+alf));
if(dcmp(alf)>eps) sol.push_back(C1.getpoint(ct-alf));
}
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 ox = (cy*(bx*bx+by*by) - by*(cx*cx+cy*cy))/d + p1.x;
double oy = (bx*(cx*cx+cy*cy) - cx*(bx*bx+by*by))/d + p1.y;
point o = point(ox, oy);
return Circle(o,dis(o,p1));
}
Circle InscribedCircle(point p1, point p2, point p3)
{
double a = dis(p2, p3);
double b = dis(p1, p3);
double c = dis(p1, p2);
point o = (p1*a+p2*b+p3*c)/(a+b+c);
return Circle(o, disPointToLine(o, p1, p2));
}
vector<double> TangentLineThroughPoint(point p,Circle c)
{
vector<double> sol;
point u=c.o-p;
double d=u.len();
if(d+eps<c.r) return sol;
else if(!dcmp(d-c.r))
{
sol.push_back(fix(angle(rotate(u,-pi/2))));
}
else
{
double alf=asin(c.r/d);
sol.push_back(fix(angle(rotate(u,-alf))));
sol.push_back(fix(angle(rotate(u,alf))));
}
sort(sol.begin(),sol.end());
return sol;
}
vector <point> CircleThroughAPointAndTangentToALineWithRadius(point o, Line L, double r) {
vector <point> sol;
point v = L.v.normal();
cirLineIntersect(Circle(o, r), Line(L.a+v*r, L.v), sol);
cirLineIntersect(Circle(o, r), Line(L.a-v*r, L.v), sol);
sort(sol.begin(), sol.end());
return sol;
}
vector <point> CircleTangentToTwoLinesWithRadius(Line L1, Line L2, double r) {
vector <point> sol;
point v1 = L1.v.normal();
point v2 = L2.v.normal();
lineLineIntersect(Line(L1.a+v1*r, L1.v), Line(L2.a+v2*r, L2.v), sol);
lineLineIntersect(Line(L1.a+v1*r, L1.v), Line(L2.a-v2*r, L2.v), sol);
lineLineIntersect(Line(L1.a-v1*r, L1.v), Line(L2.a+v2*r, L2.v), sol);
lineLineIntersect(Line(L1.a-v1*r, L1.v), Line(L2.a-v2*r, L2.v), sol);
sort(sol.begin(), sol.end());
return sol;
}
vector <point> CircleTangentToTwoDisjointCirclesWithRadius(Circle C1, Circle C2, double r) {
vector <point> sol;
cirCirIntersect(Circle(C1.o, C1.r+r), Circle(C2.o, C2.r+r), sol);
sort(sol.begin(), sol.end());
return sol;
}
string op;
void print(vector <point> sol) {
printf("[");
for(int i = 0; i < sol.size(); i++) {
sol[i].out();
if(i != sol.size()-1) printf(",");
}
printf("]\n");
}
int main() {
while(cin >> op) {
if(op == "CircumscribedCircle") {
point a, b, c;
a.in(), b.in(), c.in();
CircumscribedCircle(a, b, c).out();
}
else if(op == "InscribedCircle") {
point a, b, c;
a.in(), b.in(), c.in();
InscribedCircle(a, b, c).out();
}
else if(op == "TangentLineThroughPoint") {
Circle c; point p;
c.in(); p.in();
vector <double> ans = TangentLineThroughPoint(p, c);
printf("[");
for(int i = 0; i < ans.size(); i++) {
printf("%.6f", ans[i]);
if(i != ans.size()-1) printf(",");
}
printf("]\n");
}
else if(op == "CircleThroughAPointAndTangentToALineWithRadius") {
point p; Line l; double r;
p.in(), l.in(), scanf("%lf", &r);
print(CircleThroughAPointAndTangentToALineWithRadius(p, l, r));
}
else if(op == "CircleTangentToTwoLinesWithRadius") {
Line L1, L2; double r;
L1.in(); L2.in(); scanf("%lf", &r);
print(CircleTangentToTwoLinesWithRadius(L1, L2, r));
}
else if(op == "CircleTangentToTwoDisjointCirclesWithRadius") {
Circle c1, c2; double r;
c1.in(); c2.in(); scanf("%lf", &r);
print(CircleTangentToTwoDisjointCirclesWithRadius(c1, c2, r));
}
}
return 0;
}
自己的WA代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<string>
#include<map>
#include<vector>
#include<set>
using namespace std;
const double eps=1e-6;
const double PI=acos(-1.0);
int dcmp(double x)
{
if(fabs(x)<eps)
return 0;
return x>eps?1:-1;
}
struct Point
{
double x,y;
Point(){}
Point(double x,double y):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 -(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+eps<b.x||(!dcmp(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);
}
double DistaceToLine(Point P,Point A,Point B)
{
Vector v1=B-A,v2=P-A;
return fabs(Cross(v1,v2)/Length(v1));
}
double angle(Vector v)
{
return atan2(v.y,v.x);
}
double fix(double x)
{
if(x<-eps)
x+=PI;
return x*180.0/PI;
}
struct Line
{
Point p;
Vector v;
Line() {}
Line(Point p,Vector v):p(p),v(v){};
Point point(double t)
{
return Point(v*t+p);
}
};
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return Vector(P+v*t);
}
struct Circle
{
Point c;
double r;
Circle(Point c,double r):c(c),r(r){}
Circle() {}
Point point(double a)
{
return Point(c.x+cos(a)*r,c.y+sin(a)*r);
}
};
void getLineCircleIntersection(Line L,Circle 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=2*(a*b+c*d),g=b*b+d*d-C.r*C.r;
double delta=f*f-4*e*g;
if(delta<-eps) return;
if(delta<eps)
{
t1=t2=-f/(2*e);
sol.push_back(L.point(t1));
return;
}
t1=(-f-sqrt(delta))/(2*e);
sol.push_back(L.point(t1));
t2=(-f+sqrt(delta))/(2*e);
sol.push_back(L.point(t2));
}
void getCircleIntersection(Circle C1,Circle C2,vector<Point> &sol)
{
double d=Length(C1.c-C2.c);
if(dcmp(d-C1.r-C2.r)>0) return;
double a=angle(C2.c-C1.c);
double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
sol.push_back(C1.point(a+da));
if(dcmp(da)>eps)
sol.push_back(C1.point(a-da));
}
void work1()
{
Point A,B,C;
cin>>A.x>>A.y>>B.x>>B.y>>C.x>>C.y;
Vector p1=A-B;
Vector t1=Normal(p1);
Point mid1=(A+B)/2;
Vector p2=C-B;
Vector t2=Normal(p2);
Point mid2=(B+C)/2;
Point T=GetLineIntersection(mid1,t1,mid2,t2);
double r=Length(A-T);
printf("(%.6f,%.6f,%.6f)\n",T.x,T.y,r);
/* Point p1,p2,p3;
cin>>p1.x>>p1.y>>p2.x>>p2.y>>p3.x>>p3.y;
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);
printf("(%.6f,%.6f,%.6f)\n",p.x,p.y,Length(p1-p));
*/
}
void work2()
{
Point A,B,C;
cin>>A.x>>A.y>>B.x>>B.y>>C.x>>C.y;
Vector p1=A-B;
Vector p2=C-B;
Vector p3=C-A;
double radb=Angle(p1,p2);
double radc=Angle(p2,p3);
cout<<radb<<radc<<endl;
Vector BD=Rotate(p2,radb/2);
Vector CD=Rotate(p3,radc/2);
Point T=GetLineIntersection(B,BD,C,CD);
double r=DistaceToLine(T,A,B);
printf("(%.6f,%.6f,%.6f)\n",T.x,T.y,r);
/* Point p1,p2,p3;
cin>>p1.x>>p1.y>>p2.x>>p2.y>>p3.x>>p3.y;
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);
double r=DistaceToLine(p,p1,p2);
printf("(%.6f,%.6f,%.6f)\n",p.x,p.y,r);*/
}
void work3()
{
Circle C;
Point p;
cin>>C.c.x>>C.c.y>>C.r>>p.x>>p.y;
// Circle C(c,r);
Vector u=C.c-p;
// cout<<u.x<<endl<<u.y<<endl;
double dist=Length(u);
// cout<<dist<<endl;
if(dist+eps<C.r)
printf("[]\n");
else if(dcmp(dist-C.r)==0)
{
Vector v=Rotate(u,-PI/2);
// cout<<v.x<<endl<<v.y<<endl;
// double radd=rad+PI/2;
// if(radd==PI) radd-=PI;
printf("[%.6f]\n",fix(angle(v)));
}
else
{
double ang=asin(C.r/dist);
Vector v1=Rotate(u,-ang);
Vector v2=Rotate(u,ang);
double rad1=angle(v1);
double rad2=angle(v2);
if(rad1<rad2) swap(rad1,rad2);
printf("[%.6f,%.6f]\n",fix(rad1),fix(rad2));
}
}
void work4()
{
Point p,p1,p2;
double r;
cin>>p.x>>p.y>>p1.x>>p1.y>>p2.x>>p2.y;
cin>>r;
Line L(p1,p2-p1);
Circle C(p,r);
vector <Point> sol;
Vector cc=Normal(L.v);
getLineCircleIntersection(Line(L.p+cc*r,L.v),C,sol);
getLineCircleIntersection(Line(L.p-cc*r,L.v),C,sol);
sort(sol.begin(),sol.end());
// cout<<sol.size()<<endl;
cout<<"[";
for(int i=0;i<sol.size();i++)
{
printf("(%.6f,%.6f)",sol[i].x,sol[i].y);
if(i!=sol.size()-1) cout<<",";
}
cout<<"]"<<endl;
}
void work5()
{
Point p1,p2,p3,p4;
double r;
cin>>p1.x>>p1.y>>p2.x>>p2.y>>p3.x>>p3.y>>p4.x>>p4.y>>r;
Line L1(p1,p2-p1),L2(p3,p4-p3);
Vector LN1=Normal(L1.v);
Vector LN2=Normal(L2.v);
vector <Point> sol;
sol.push_back(GetLineIntersection(L1.p+LN1*r,L1.v,L2.p+LN2*r,L2.v));
sol.push_back(GetLineIntersection(L1.p+LN1*r,L1.v,L2.p-LN2*r,L2.v));
sol.push_back(GetLineIntersection(L1.p-LN1*r,L1.v,L2.p+LN2*r,L2.v));
sol.push_back(GetLineIntersection(L1.p-LN1*r,L1.v,L2.p-LN2*r,L2.v));
sort(sol.begin(),sol.end());
cout<<"[";
for(int i=0;i<sol.size();i++)
{
printf("(%.6f,%.6f)",sol[i].x,sol[i].y);
if(i!=sol.size()-1) cout<<",";
}
cout<<"]"<<endl;
}
void work6()
{
Circle C1,C2;
double r;
cin>>C1.c.x>>C1.c.y>>C1.r>>C2.c.x>>C2.c.y>>C2.r>>r;
vector<Point> sol;
getCircleIntersection(Circle(C1.c,C1.r+r),Circle(C2.c,C2.r+r),sol);
sort(sol.begin(),sol.end());
cout<<"[";
for(int i=0;i<sol.size();i++)
{
printf("(%.6f,%.6f)",sol[i].x,sol[i].y);
if(i!=sol.size()-1) cout<<",";
}
cout<<"]"<<endl;
}
int main()
{
string s;
while(cin>>s)
{
if(s=="CircumscribedCircle")
work1();
else if(s=="InscribedCircle")
work2();
else if(s=="TangentLineThroughPoint")
work3();
else if(s=="CircleThroughAPointAndTangentToALineWithRadius")
work4();
else if(s=="CircleTangentToTwoLinesWithRadius")
work5();
else if(s=="CircleTangentToTwoDisjointCirclesWithRadius")
work6();
}
return 0;
}