HDU 4998 Rotate (2014年鞍山赛区网络赛B题)

1.题目描述:点击打开链接

2.解题思路:本题属于几何变换专题,一开始想着随便枚举两个点,然后都进行一下旋转变换,最后利用原始点和旋转后的点所在直线的中垂线的交点求解。然而发现精度损失很大,而且可能有特殊情况没有考虑到。学习了一下几何变换的方法。

       由于旋转操作相当于对一个点构成的矩阵和一个旋转矩阵做乘法运算。最基本的旋转变换就是任意一个点围绕原点进行逆时针旋转。如果改成围绕某个定点(x0,y0)进行旋转可以分解为三步:将被旋转点平移(-x0,-y0),进行基本旋转变换,再平移(x0,y0)。在矩阵中可以理解为三个变换矩阵相乘。本题中,经过n次旋转操作后,得到最终的旋转矩阵ans。通过解一个二元一次方程组即可求得最终的旋转点。

详细的几何变换的讲解请看:点击打开链接 ,本题即该博客的情况2.5的应用。

3.代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
using namespace std;

#define me(s) memset(s,0,sizeof(s))
#define pb push_back
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;


const double eps=1e-8;
const double PI=acos(-1.0);

struct Tran  //定义一个结构体,支持输入操作,矩阵相乘操作
{
    double x,y,r;
    double v[3][3];
    Tran()
    {
       memset(v,0,sizeof(v));
    }
    void init()
    {
        scanf("%lf%lf%lf",&x,&y,&r);
        memset(v,0,sizeof(v));
        v[0][0]=cos(r);v[0][1]=sin(r);
        v[1][0]=-sin(r);v[1][1]=cos(r);
        v[2][0]=x*(1-cos(r))+y*sin(r);
        v[2][1]=y*(1-cos(r))-x*sin(r);
        v[2][2]=1;
    }
    Tran operator*(Tran c)
    {
        Tran ans;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
            for(int k=0;k<3;k++)
            ans.v[i][j]+=v[i][k]*c.v[k][j];
        return ans;
    }
}tran[15];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        Tran ans; //ans矩阵为旋转n次后的矩阵
        for(int i=0;i<3;i++)
            ans.v[i][i]=1;//设置初始矩阵为单位矩阵
        for(int i=0;i<n;i++)
           {
               tran[i].init();
               ans=ans*tran[i];//进行n次相乘
           }
        double r=atan2(ans.v[0][1],ans.v[0][0]);
        if(r<0)r=2*PI+r;
        double cosr=ans.v[0][0];
        double sinr=ans.v[0][1];
        double b2=1-cosr;
        double b1=sinr;
        double c1=ans.v[2][0];
        double c2=ans.v[2][1];
        double M=b2*b2+b1*b1;
        double x=(b2*c1-b1*c2)/M;//利用行列式求解x,y
        double y=(b2*c2+b1*c1)/M;
        printf("%.10lf %.10lf %.10lf\n",x,y,r);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值