这是一道几何模板题,但是难度就在于把六种几何问题放在了一起,代码一长就不好改错。另外在训练指南上面的翻译只是把大致意思翻译了,有些细节没有翻译出来。比如说答案里面数值的排序要按照从小到大的顺序,点的顺序也要进行排序。
第一个问题没有按照训练指南上面的方法做,我用垂直平分线的交点来做的。
代码如下:
#include<iostream>
#include<cmath>
#include<stdlib.h>
#include<iomanip>
#include<stack>
#include<algorithm>
using namespace std;
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 -(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<b.x||(a.x==b.x&&a.y<b.y);}
const double eps=1e-10;
int dcmp(double x){
if(fabs(x)<eps)return 0;
else return (x<0?-1:1);
}
bool operator == (point a,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 lenth(vector a){return sqrt(dot(a,a));}
double cross(vector a,vector b){return a.x*b.y-a.y*b.x;}
double angle(vector a,vector b){return acos(dot(a,b)/lenth(a)/lenth(b));}
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;
}
double distancetoline(point p,point a,point b){//µãµ½Ö±Ïß
vector v1=a-b,v2=p-a;
return (fabs(cross(v1,v2))/lenth(v1));
}
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 angle2(vector v){return atan2(v.y,v.x);}
struct line{
point p;
vector v;
line(point p,vector v):p(p),v(v){}
};
struct circle{
point c;
double r;
circle(point c=point(0,0),double r=0):c(c),r(r){}
};
void CircumscribeCircle(point p1,point p2,point p3){
point p12=(p1+p2)/2;
vector v12=p1-p2;
v12=vector(v12.y,-v12.x);
point p23=(p2+p3)/2;
vector v23=p2-p3;
v23=vector(v23.y,-v23.x);
point c=getlineintersection(p12,v12,p23,v23);
double r=lenth(p1-c);
cout<<setiosflags(ios::fixed)<<setprecision(6)<<'('<<c.x<<','<<c.y<<','<<r<<')'<<endl;
// return circle(c,r);
}
void inscribedcircle(point p1,point p2,point p3){
double a=lenth(p2-p3);
double b=lenth(p3-p1);
double c=lenth(p1-p2);
point p=(p1*a+p2*b+p3*c)/(a+b+c);
cout<<setiosflags(ios::fixed)<<setprecision(6)<<'('<<p.x<<','<<p.y<<','<<distancetoline(p,p1,p2)<<')'<<endl;
// return circle(p,distancetoline(p,p1,p2));
}
void tangentlinethroughpoint(circle C,point p){
vector u=C.c-p;
double dist=lenth(u);
if(dcmp(dist-C.r)<0){
cout<<'['<<"]"<<endl;
return ;
}
else if(dcmp(dist-C.r)==0){
u=vector(u.y,-u.x);
double ang=atan(u.y/u.x)/3.14159265358979*180;
if(ang<0){
ang+=180;//changed
}
cout<<setiosflags(ios::fixed)<<setprecision(6)<<'['<<ang<<']'<<endl;//changed
return ;
}
else{
double ang=asin(C.r/dist);
vector v1=rotate(u,ang);
vector v2=rotate(u,-ang);
double angle1=atan(v1.y/v1.x)/3.14159265358979*180;
if(angle1<0)angle1+=180;
double angle2=atan(v2.y/v2.x)/3.14159265358979*180;
if(angle2<0)angle2+=180;
if(angle2<angle1){
double tmp=angle1;
angle1=angle2;
angle2=tmp;
}
cout<<setiosflags(ios::fixed)<<setprecision(6)<<'['<<angle1<<','<<angle2<<']'<<endl;
return ;
}
}
int getlinecircleintersection(line L,circle C,stack<point>& sol){//check
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;
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(distancetoline(C.c,L.p,L.v+L.p)-C.r)==0)delta=0;//L是计算出来的,不是输入的,所以可能有误差,这里去掉误差
// cout<<"distance="<<distancetoline(C.c,L.p,L.v+L.p)<<" C.r="<<C.r<<endl;
// cout<<"delta="<<delta<<endl;
if(dcmp(delta)<0)return 0;
if(dcmp(delta)==0){
double t1=-f/(2*e);
point p(L.p.x+t1*L.v.x,L.p.y+t1*L.v.y);
sol.push(p);
// cout<<'['<<'('<<p.x<<','<<p.y<<')'<<']'<<endl;
return 1;
}
// cout<<"zzzzzzzzzz"<<f<<endl;
delta=sqrt(delta);
double t1=(-f-delta)/(2*e);
double t2=(-f+delta)/(2*e);
point p1(L.p.x+t1*L.v.x,L.p.y+t1*L.v.y);
point p2(L.p.x+t2*L.v.x,L.p.y+t2*L.v.y);
sol.push(p1);
sol.push(p2);
// cout<<'['<<'('<<p1.x<<','<<p1.y<<')'<<','<<'('<<p2.x<<','<<p2.y<<')'<<']'<<endl;
return 2;
}
void circlethroughapointandtangenttoalinewithradius(point xp,point x1,point x2,double r){//check
line xx(x1, (x2-x1) );
// double tmp=cross(xx.p-x1,xx.v);
double ang=atan(xx.v.y/xx.v.x);
stack<point> sol;
if(dcmp(ang)!=0)
{
double mov=r/sin(ang);
line l1(point(x1.x-mov,x1.y),x2-x1);
circle C(xp,r);
int tmp=getlinecircleintersection(l1,C,sol);
line l2(point(x1.x+mov,x1.y),x2-x1);
tmp+=getlinecircleintersection(l2,C,sol);
if(!tmp){cout<<'['<<']'<<endl;return ;}
}
else{
double mov=r;
line l1(point(x1.x,x1.y+r),x2-x1);
line l2(point(x1.x,x1.y-r),x2-x1);
circle C(xp,r);
int tmp=getlinecircleintersection(l1,C,sol);
tmp+=getlinecircleintersection(l2,C,sol);
if(!tmp){cout<<'['<<']'<<endl;return;}
}
point solve[4];
int tot=0;
while(!sol.empty()){
solve[tot++]=sol.top();
sol.pop();
}
sort(solve,solve+tot);
cout<<'[';
for(int i=0;i<tot;++i){
cout<<setiosflags(ios::fixed)<<setprecision(6)<<'('<<solve[i].x<<','<<solve[i].y<<')';
if(i<tot-1)cout<<',';
}
cout<<']'<<endl;
}
void circletangenttotwolineswithradius(point x1,point x2,point x3,point x4,double r){//changed
vector v1=x2-x1;
vector v2=x4-x3;
point xz=getlineintersection(x1,v1,x3,v2);
// line L2(xz,v2);
// line L1(xz,v1);
point C[4];
int tot=4;
vector v11(-v1.y,v1.x);
vector v22(-v2.y,v2.x);
point xt1=xz+v11/lenth(v11)*r;
point xt2=xz+v22/lenth(v22)*r;
C[0]=getlineintersection(xt1,v1,xt2,v2);
C[1]=xz+(xz-C[0]);
point xt11=xz-v11/lenth(v11)*r;
C[2]=getlineintersection(xt11,v1,xt2,v2);
C[3]=xz+(xz-C[2]);
sort(C,C+tot);
cout<<'[';
for(int i=0;i<4;++i){
cout<<'('<<C[i].x<<','<<C[i].y<<')';
if(i<3)cout<<',';
}
cout<<']'<<endl;
// cout<<setiosflags(ios::fixed)<<setprecision(6)<<'['<<'('<<C1.x<<','<<C1.y<<')'<<','<<'('<<C2.x<<','<<C2.y<<')'<<','<<'('<<C3.x<<','<<C3.y<<')'<<','<<'('<<C4.x<<','<<C4.y<<')'<<']'<<endl;
}
void CircleTangentToTwoDisjointCirclesWithRadius(point p1,double r1,point p2,double r2,double rr){
double d2=lenth(p2-p1);
if(dcmp(d2-r1-r2-rr-rr)==0){
point C=p1+(p2-p1)/d2*(r1+rr);
cout<<setiosflags(ios::fixed)<<setprecision(6)<<'['<<'('<<C.x<<','<<C.y<<')'<<']'<<endl;
return ;
}
else if(dcmp(d2-r1-r2-rr-rr)>0){
cout<<'['<<']'<<endl;
return ;
}
else{
double a=rr+r2;
double b=rr+r1;
double c=d2;
double ang1=acos((b*b+c*c-a*a)/2/b/c);
// cout<<a<<' '<<b<<' '<<c<<"cos="<<(b*b+c*c-a*a)/2/b/c<<endl;
// cout<<"ang1="<<ang1<<endl;
vector vv1=rotate(p2-p1,ang1);
double ang2=acos((a*a+c*c-b*b)/2/a/c);
vector vv2=rotate(p1-p2,-ang2);
point C1=getlineintersection(p1,vv1,p2,vv2);
vv1=rotate(p2-p1,-ang1);
vv2=rotate(p1-p2,ang2);
point C2=getlineintersection(p1,vv1,p2,vv2);
if(C2<C1){
point tmp=C1;
C1=C2;
C2=tmp;
}
cout<<setiosflags(ios::fixed)<<setprecision(6)<<'['<<'('<<C1.x<<','<<C1.y<<')'<<','<<'('<<C2.x<<','<<C2.y<<')'<<']'<<endl;
return ;
}
}
int main(){
// freopen("data.txt","r",stdin);
ios::sync_with_stdio(false);
string ind;
while(cin>>ind){
if(ind=="CircumscribedCircle"){
point x1,x2,x3;
cin>>x1.x>>x1.y>>x2.x>>x2.y>>x3.x>>x3.y;
CircumscribeCircle(x1,x2,x3);
}
else if(ind=="InscribedCircle"){
point x1,x2,x3;
cin>>x1.x>>x1.y>>x2.x>>x2.y>>x3.x>>x3.y;
inscribedcircle(x1,x2,x3);
}
else if(ind=="TangentLineThroughPoint"){
circle C;
point p;
cin>>C.c.x>>C.c.y>>C.r>>p.x>>p.y;
tangentlinethroughpoint(C,p);
}
else if(ind=="CircleThroughAPointAndTangentToALineWithRadius"){
point xp,x1,x2;
double r;
cin>>xp.x>>xp.y>>x1.x>>x1.y>>x2.x>>x2.y>>r;
circlethroughapointandtangenttoalinewithradius(xp,x1,x2,r);
}
else if(ind=="CircleTangentToTwoLinesWithRadius"){
point x1,x2,x3,x4;
double r;
cin>>x1.x>>x1.y>>x2.x>>x2.y>>x3.x>>x3.y>>x4.x>>x4.y>>r;
circletangenttotwolineswithradius(x1,x2,x3,x4,r);
}
else if(ind=="CircleTangentToTwoDisjointCirclesWithRadius"){
point p1,p2;
double r1,r2,rr;
cin>>p1.x>>p1.y>>r1>>p2.x>>p2.y>>r2>>rr;
CircleTangentToTwoDisjointCirclesWithRadius(p1,r1,p2,r2,rr);
}
}
return 0;
}