现在的位置: 首页 > 综合 > 正文

hdu 4998 Rotate 2014 ACM/ICPC Asia Regional Anshan Online

2018年04月25日 ⁄ 综合 ⁄ 共 2680字 ⁄ 字号 评论关闭

蒟蒻表示计算几何一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;
}



抱歉!评论已关闭.