problem
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
3
0.5 0
2.5 2
-4.5 1
Trans(1.5,-1)
Loop(2)
Trans(1,1)
Loop(2)
Rotate(90,0,0)
End
Scale(2,3)
End
Sample Output
10.0000 -3.0000
18.0000 15.0000
-10.0000 6.0000
Data Constraint
保证操作中坐标值不会超过double范围,输出不会超过int范围;
指令总共不超过1000行;
对于所有的数据,所有循环指令中m<=1000000;
对于60%的数据,所有循环指令中m<=1000;
对于30%的数据不含嵌套循环。
Hint
【友情提醒】
pi的值最好用系统的值。C++的定义为:#define Pi M_PI
Pascal就是直接为:pi
不要自己定义避免因为pi带来的误差。
analysis
30%的数据用模拟美滋滋地就能水分,但是——
指令总共不超过1000行;对于所有的数据,所有循环指令中m<=1000000
100%数据模拟GG
正解仍旧是矩阵乘法!
可以发现,对一个Loop—End循环操作m次,相当于乘上某个和谐的矩阵
所以就需要矩阵乘法来解决模拟太慢的问题了
构造矩阵式
首先这道 蜜汁 计算几何的题目需要一个旋转公式
如何构造矩阵?
设A=(x,y,1)(添加无用常数项),分别构造T1,T2,T3使:
我们经过一番和谐拆项以后,得到这三个东东:
得到三个转移矩阵,套上一个栈模拟或dfs,就可以了
初始时A=⎛⎝⎜1,0,00,1,00,0,1⎞⎠⎟(零矩阵)每退出一个Loop—End循环,就分三类情况累乘A矩阵
最后把每个点都乘上
code
这题好像没怎么卡精度,好评
#include<bits/stdc++.h>
#define Pi 3.14159265358979323846264338327950
using namespace std;
struct matrix
{
double m[3][3];
};
matrix door[101];
char st[101];
int n;
matrix I=
{
1,0,0,
0,1,0,
0,0,1
};
matrix operator *(matrix a,matrix b)
{
matrix c;
for (int i=0;i<=2;i++)
{
for (int j=0;j<=2;j++)
{
c.m[i][j]=0;
for (int k=0;k<=2;k++)c.m[i][j]+=a.m[i][k]*b.m[k][j];
}
}
return c;
}
matrix power(matrix a,int k)
{
matrix ans=I,p=a;
while (k)
{
if (k&1)ans=ans*p;
p=p*p;
k/=2;
}
return ans;
}
matrix dfs(int t)
{
matrix a,tmp1,tmp2,tmp3;
a=tmp1=
{
1,0,0,
0,1,0,
0,0,1
};
tmp2.m[2][2]=1;
tmp3.m[2][2]=1;
int now;
for (scanf("%s",st);*st!='E';scanf("%s",st))
{
double theta,x,y;
switch (*st)
{
case 'T':
{
sscanf(st,"Trans(%lf,%lf",&tmp1.m[2][0],&tmp1.m[2][1]);
a=a*tmp1;
}
break;
case 'S':
{
sscanf(st,"Scale(%lf,%lf",&tmp2.m[0][0],&tmp2.m[1][1]);
a=a*tmp2;
}
break;
case 'R':
{
sscanf(st,"Rotate(%lf,%lf,%lf",&theta,&x,&y);
double _sin=sin(-theta/180*Pi),_cos=cos(-theta/180*Pi);
tmp3=
{
_cos,_sin,0,
-_sin,_cos,0,
x-x*_cos+y*_sin,y-x*_sin-y*_cos,1
};
a=a*tmp3;
}
break;
default:
{
sscanf(st,"Loop(%d",&now);
a=a*dfs(now);
}
}
}
return power(a,t);
}
int main()
{
freopen("transform.in","r",stdin);
freopen("transform.out","w",stdout);
//freopen("readin.txt","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lf%lf",&door[i].m[0][0],&door[i].m[0][1]);
door[i].m[0][2]=1;
}
matrix a,tmp1,tmp2,tmp3;
a=tmp1=
{
1,0,0,
0,1,0,
0,0,1
};
tmp2.m[2][2]=1;
tmp3.m[2][2]=1;
while (scanf("%s",st)==1)
{
double theta,x,y;
switch (*st)
{
case 'T':
{
sscanf(st,"Trans(%lf,%lf",&tmp1.m[2][0],&tmp1.m[2][1]);
a=a*tmp1;
}
break;
case 'S':
{
sscanf(st,"Scale(%lf,%lf",&tmp2.m[0][0],&tmp2.m[1][1]);
a=a*tmp2;
}
break;
case 'R':
{
sscanf(st,"Rotate(%lf,%lf,%lf",&theta,&x,&y);
double _sin=sin(-theta/180*Pi),_cos=cos(-theta/180*Pi);
tmp3=
{
_cos,_sin,0,
-_sin,_cos,0,
x-x*_cos+y*_sin,y-x*_sin-y*_cos,1
};
a=a*tmp3;
}
break;
default:
{
int x;
sscanf(st,"Loop(%d",&x);
a=a*dfs(x);
}
}
}
for (int i=1;i<=n;i++)
{
printf("%.4lf %.4lf\n",(door[i]*a).m[0][0],(door[i]*a).m[0][1]);
}
return 0;
}