蒟蒻表示计算几何一WA就手足无措啊。。还要care一下精度问题。
因为最多旋转十次,直接取一个向量模拟,最后算旋转夹角就行了。注意这里面角度结果的范围是[0,2*pi),而acos的范围是[0,pi),所以最后要根据叉积判断夹角有木有超Pi。
然后旋转中心通过轨迹中垂线求解,我之前把这个和两条直线的交点弄混了。==
#include<iostream> #include<stdio.h> #include<cstdio> #include<stdlib.h> #include<vector> #include<string> #include<cstring> #include<cmath> #include<algorithm> #include<stack> #include<queue> #include <ctype.h> using namespace std; //hdu 4998 int T; int n; double pi=acos(-1.0); const double eps=1e-11; struct Point { double x; double y; Point(double x=0,double y=0):x(x),y(y) { } }; typedef Point Vector; const double esp=1e-10; 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 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); } double Cross(Vector A,Vector B) { return A.x*B.y-A.y*B.x; } 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 Dot(Vector A,Vector B) { return A.x*B.x+A.y*B.y; } double Length(Vector A) { return sqrt(Dot(A,A)); } Vector Normal(Vector A) { double L=Length(A); return Vector(-A.y/L,A.x/L); } double Angle(Vector A, Vector B) { return acos(Dot(A,B)/Length(A)/Length(B));//acos返回的是0-pi的弧度,而题目中是0 to 2pi } Point rotcen[15]; double p[15]; Point st0;//初始直线位置 Point ed0; Point st;//旋转最后的直线位置 Point ed; void input() { scanf("%d",&n); memset(p,0,sizeof(p)); for(int i=0;i<n;i++) { scanf("%lf %lf %lf",&rotcen[i].x,&rotcen[i].y,&p[i]); } // st0=Point(rotcen[0].x-1,rotcen[0].y-1); // ed0=Point(rotcen[0].x+1,rotcen[0].y);//不能随手设个初值,要防止旋转点和初值为同一点 st0=Point(-1,-1); ed0=Point(1,0);//随手设个初值也行。。 } void run() { Point sttmp=st0; Point edtmp=ed0; for(int i=0;i<n;i++) { Vector tmp=sttmp-rotcen[i];//要转化成在原点旋转的情况 sttmp=Rotate(tmp,p[i])+rotcen[i]; tmp=edtmp-rotcen[i]; edtmp=Rotate(tmp,p[i])+rotcen[i]; // cout<<sttmp.x<<" "<<sttmp.y<<" "<<edtmp.x<<" "<<edtmp.y<<endl; } st=sttmp; ed=edtmp; //st0,st ed0,ed的连线的垂直平分线交点才是旋转中心,不是两条直线旋转的交点 Point P=Point(0.5*(st0.x+st.x),0.5*(st0.y+st.y)); Point Q=Point(0.5*(ed0.x+ed.x),0.5*(ed0.y+ed.y)); Vector v=Normal(st-st0); Vector w=Normal(ed-ed0); Point center=GetLineIntersection(P,v,Q,w); //double ang=Angle(st-st0,ed-ed0);//应该是绕旋转中心的旋转角,不是两条直线的夹角 double ang=Angle(st-center,st0-center); // cout<<Cross(st-center,st0-center) <<endl; if(Cross(st-center,st0-center)> 0)//叉乘默认逆时针为正,>0则旋转的角度>pi ang = 2 * pi - ang; // Vector t3=st0-center,t4=st-center;//直接用几何的方法算也行 // double ang=atan2(t4.y,t4.x)-atan2(t3.y,t3.x);//new-old // if(ang<eps)//用atan2相减算ang时,没有这个特判会WA // { // ang+=2*pi; // } printf("%.10lf %.10lf %.10lf\n",center.x,center.y,ang); } int main() { freopen("input.txt","r",stdin); // freopen("data.txt","r",stdin); //freopen("out1.txt","w",stdout); scanf("%d",&T); for(int i=0;i<T;i++) { input(); run(); } return 0; }