nyoj 298

http://acm.nyist.net/JudgeOnline/problem.php?pid=298
给定n个点,m个操作,构造O(m+n)的算法输出m个操作后各点的位置。操作有平移、缩放、翻转和旋转。
这里的操作是对所有点同时进行的。其中翻转是以坐标轴为对称轴进行翻转(两种情况),旋转则以原点为中心。如果对每个点分别进行模拟,那么m个操作总共耗 时O(mn)。利用矩阵乘法可以在O(m)的时间里把所有操作合并为一个矩阵,然后每个点与该矩阵相乘即可直接得出最终该点的位置,总共耗时 O(m+n)。假设初始时某个点的坐标为x和y,下面5个矩阵可以分别对其进行平移、旋转、翻转和旋转操作。预先把所有m个操作所对应的矩阵全部乘起来, 再乘以(x,y,1),即可一步得出最终点的位置。

绕原点旋转的公式可由两点的叉积和点积方程联立求解。
虽然样例没跑过(0.0输出-0.0),还是抱着必A的决心交了,AC了。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#define mem(x,y) memset(x,y,sizeof(x))
#define inf 0x3f3f3f3f
using namespace std;
#define siz 3
#define MAXN 10000+5
#define pi acos(-1)
struct matrix
{
double a[siz][siz];
};
matrix multi(matrix &x,matrix &y)
{

matrix res;
mem(res.a,0);
for(int i=0;i<siz;i++)
for(int j=0;j<siz;j++)
if(x.a[i][j])
for(int k=0;k<siz;k++)
res.a[i][k]+=x.a[i][j]*y.a[j][k];
return res;
}
double x[MAXN],y[MAXN];
int main()
{

int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%lf%lf",&x[i],&y[i]);
matrix ans;
mem(ans.a,0);
for(int i=0;i<siz;i++)
ans.a[i][i]=1;
while(m--)
{
char s[5];
double a,b;
scanf("%s",s);
matrix k;
mem(k.a,0);
for(int i=0;i<3;i++)
k.a[i][i]=1;
switch(s[0])
{
case 'M':
scanf("%lf%lf",&a,&b);
k.a[0][2]=a;
k.a[1][2]=b;
break;
case 'X':
k.a[1][1]=-1;
break;
case 'Y':
k.a[0][0]=-1;
break;
case 'S':
scanf("%lf",&a);
k.a[0][0]=k.a[1][1]=a;
break;
case 'R':
scanf("%lf",&a);
a*=pi/180.0;
k.a[0][0]=cos(a);
k.a[0][1]=-sin(a);
k.a[1][0]=sin(a);
k.a[1][1]=cos(a);
break;
default:
break;
}
ans=multi(k,ans);
}
for(int i=0;i<n;i++)
{
double x1=x[i]*ans.a[0][0]+y[i]*ans.a[0][1]+ans.a[0][2];
double y1=x[i]*ans.a[1][0]+y[i]*ans.a[1][1]+ans.a[1][2];
printf("%.1lf %.1lf\n",x1,y1);
}
}

EOF