题意:
给你一些点的坐标和绕每个点旋转的弧度值,现在假设有一个平面,依次按照以每个点为圆心逆时针旋转每个给出的弧度值,问你经过这么多次旋转之后相当于绕哪个点逆时针旋转了多少弧度。
思路:
这道题还是比较好的,数据量比较小,想到暴力的方法把它模拟出来就能过。
那么我们要考虑怎样模拟。
题中点的范围在(0,0)~(100,100)之间,考虑到要确定一个平面,只需要三个不在同一直线上的点就行了,这里我们为了方便,取不在题中数据范围内的三个点 AA(101,100), BB(101,1), CC(0,101)。那么,每次这三个点按题意旋转,转到最后连接每个点前后对应的点,取中垂线,这三个中垂线必定交于一点,这一点就是最后求得的中心点,然后前后两个点和圆心组成了三角形,根据余弦定理求得角度,进而得到弧度值。如下图。
这里我们的根据是kuangbin大神的两个模板,1.求一个点以(0,0)为中心旋转B弧度后的点。2.求两条直线的交点坐标。
当然,这个模板不改的话在这个题中是不能用的。对第一个模板,我们修改它的参数,使其包括起点,中心点和弧度值。我们先把起点和中心点连成的线段的中心点对齐到(0,0),也就是相当于起点横纵坐标减去中心点的横纵坐标,然后套模板,得到假如中心点是(0,0),旋转后的坐标,接着把旋转后的坐标加上中心点的坐标就是求任意点绕任意中心旋转后的点了。
另一个模板使用时要有两条线,线的定义是用两个点完成的,现在考虑如何获得一条线段的中垂线。以线段AA AA'为例,两个点的坐标我们是知道的,中点坐标也很好求,这时注意到我们上面已经有了一个可以求任意点绕任意中心旋转的函数,我们把AA点绕着中点旋转90度之后的点和中点正好就是中垂线,这样我们就可以求得答案中的中心点了。
求弧度值这里需要注意一下,我是根据已知的三点坐标构造三角形利用余弦定理求得的,这里求的角度只会是小于180°的,然而题中最后答案会出现大于180°小于360°所对应的弧度值,那么我们求完弧度值之后再套用刚才改的函数,如果和我们正常求得的点对应上的话就是小于180°的弧度值,否则就是2π-所求的弧度值。注意判断的时候不要用!=,因为double类型算的时候有误差,想相等很难,用精度控制判断相等与否。
#include <bits/stdc++.h>
const double pi = acos (-1.0);
const double eps=1e-6;
using namespace std;
struct Point{
double x,y,b;
Point(){}
Point(double _x,double _y)
{
x=_x;y=_y;
}
Point operator -(const Point &b)const
{
return Point(x-b.x,y-b.y);
}
double operator ^(const Point &b)const
{
return x*b.y-y*b.x;
}
void trans(double B)
{
double tx=x,ty=y;
x=tx*cos(B)-ty*sin(B);
y=tx*sin(B)+ty*cos(B);
}
}a[15];
void zhuan(Point &A,Point &B,double b)
{
A.x-=B.x;
A.y-=B.y;
A.trans(b);
A.x+=B.x;
A.y+=B.y;
}
Point AA(101,100),BB(101,1),CC(0,101);///初始的三个点
struct Line{
Point s,e;
Line(){}
Line(Point _s,Point _e)
{
s=_s;e=_e;
}
pair<int,Point> operator &(const Line &b)const{
Point res=s;
double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
res.x+=(e.x-s.x)*t;
res.y+=(e.y-s.y)*t;
return make_pair(2,res);
}
};
double dist(Point A,Point B)
{
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
double qiuhudu(Point C,Point ans1,Point CC)
{
double a=dist(C,ans1);
double b=dist(CC,ans1);
double c=dist(C,CC);
double ans=(a*a+b*b-c*c)/2/a/b;
return acos(ans);
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
Point A(101,100),B(101,1),C(0,101);///为了方便比较另设三个相同的点
for(int i=0;i<n;i++)
{
scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].b);
zhuan(A,a[i],a[i].b);
zhuan(B,a[i],a[i].b);
zhuan(C,a[i],a[i].b);///三个点每次都旋转
}
Point mid1((A.x+AA.x)/2,(A.y+AA.y)/2);
Point mid2((B.x+BB.x)/2,(B.y+BB.y)/2);
zhuan(A,mid1,pi/2);
Line A1(A,mid1);///A AA线段的中垂线
zhuan(B,mid2,pi/2);
Line A2(B,mid2);///B BB线段的中垂线
pair<int,Point>s=A1&A2;///建立一个s是A1 A2相交的点,因为此题必定相交,模板有舍弃
Point ans1(s.second.x,s.second.y);
double ans2=qiuhudu(C,ans1,CC);//cout<<"qiude ="<<ans2<<" ";
//cout<<ans2<<endl;
Point temp(CC.x,CC.y);
zhuan(temp,ans1,ans2);
if(fabs(temp.x-C.x)>eps||fabs(temp.y-C.y)>eps)///C点没动,拿C点比较
ans2=2*pi-ans2;
/*cout<<"CC"<<CC.x<<" "<<CC.y<<endl;
cout<<"C"<<C.x<<" "<<C.y<<endl;
cout<<"temp"<<temp.x<<" "<<temp.y<<endl;*/
printf("%.10f %.10f %.10f\n",s.second.x,s.second.y,ans2);
}
return 0;
}