图形变换(transform)
Description
对一个由n个点组成的图形连续作平移、缩放、旋转变换。相关操作定义如下:
Trans(dx,dy) 表示平移图形,即把图形上所有的点的横纵坐标分别加上dx和dy;
Scale(sx,sy) 表示缩放图形,即把图形上所有点的横纵坐标分别乘以sx和sy;
Rotate(θ,x0,y0) 表示旋转图形,即把图形上所有点的坐标绕(x0,y0)顺时针旋转θ角度
由于某些操作会重复运行多次,还定义了循环指令:
Loop(m)
…
End
表示把Loop和对应End之间的操作循环执行m次,循环可以嵌套。
Input
第一行一个整数n(n<=100)表示图形由n个点组成;
接下来n行,每行空格隔开两个实数xi,yi表示点的坐标;
接下来一直到文件结束,每行一条操作指令。保证指令格式合法,无多余空格。
Output
输出有n行,每行两个空格隔开实数xi,yi表示对应输入的点变换后的坐标。
本题采用Special Judge判断,只要你输出的数值与标准答案误差不能超过1即可。
Sample Input
1 | 3 |
Sample Output
1 | 10.0000 -3.0000 |
Data Constraint
保证操作中坐标值不会超过double范围,输出不会超过int范围;
指令总共不超过1000行;
对于所有的数据,所有循环指令中m<=1000000;
对于60%的数据,所有循环指令中m<=1000;
对于30%的数据不含嵌套循环。
Analysis
看到这道题,首先想到的肯定是模拟。平移和缩放都是很简单的操作,比较麻烦的是旋转操作。据说有一个公式可以求任意点绕着原点逆时针旋转θrad的公式。
因为题目要求的是顺时针我们将角度取反再加上2πrad就好了。对于绕着任一点旋转,我们可以平移所有的点,使得给定的点与原点重合,套用公式计算,再把所有的平移回去。这样就可以通过暴力模拟拿到30%的分了。
因为循环的次数非常大,而给出的指令又比较少,所以我们应该想办法将循环之间的状态保存下来然后快速的做n次。因为我们注意到题目中的变换是对于两个变量的线性递推,所以可以用矩阵来实现。而每做一次相当于矩阵自乘一次。因为矩阵具有结合律,所以自乘的操作通过快速幂来实现就好了。
我们可以将每一种操作用矩阵表示出来,O(M)的扫一遍整个指令后将每个矩阵相乘,即可得到做完所有操作后的最终矩阵。然后,我们O(N)的将每一个点都与这个矩阵相乘就能得到这个点经过M次操作后的最终结果了。
接下来就是如何构造矩阵的问题了。平移,缩放的矩阵构造相对简单。基本上是通过系数于变量相乘和相加而得,具体可看程序实现。(可以自己手动模拟模拟矩阵乘法的工作过程)
比较难得就是旋转的矩阵构造。
我们不需要将一个旋转命令拆成几个命令,这样子太麻烦。可以一步构造矩阵实现平移与绕远点旋转。
我们假设图形中的一个点为(x,y),绕(x0,y0)这个点顺时针旋转θrad(可以通过取反再加上一圈转换),那么举例说明x’是如何得到的。
x’ = (x-x0)cosθ-(y-y0)sinθ+x0=cosθx-sinθy+sinθy0-cosθx0+x0
y’ = 同理可得
最后的矩阵就是这样的:
| –|1 | 2 | 3 |
| –|:-:| :|
| 1 | cosθ | sinθ | 0
| 2 | -sinθ | cosθ |0
| 3 | sinθy0-cosθx0+x0 | cosθy0-sinx0+y0 |1
对于每一个点构造矩阵:
| –|1 | 2 | 3 |
| –|:-:| :|
| 1 | x | y | 0
| 2 | 0 | 0 |0
| 3 | 0 | 0 |0
最后就可以在O(M)的时间过啦~~~
Code
1 |
|