您的位置:首页 > 其它

【NOIP2013模拟联考14】图形变换(transform)

2017-10-02 15:27 411 查看
【NOIP2013模拟联考14】图形变换(transform)

(File IO): input:transform.in output:transform.out

Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits Special Judge

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判断,只要你输出的数值与标准答案
4000
误差不能超过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带来的误差。

正解

其实思路很简单,只要你学过矩阵乘法就行了。

矩阵乘法

用处

矩阵乘法是一种能将线性递推的O(n)做到O(log2 n)的好方法。

定义

矩阵乘法的定义是对于a矩阵与b矩阵,他们的乘积c矩阵的递推式为 c[i,j]=a[i,k]*b[k,j]。

注意事项

只满足结合律,不满足交换律。

用法

用在一些常数项的递推式中。

例如:斐波那契数列。f[i]=f[i-1]+f[i-2]

先建设a,b矩阵。b矩阵是一个2*1的矩阵 b[n,1,1]=f
,b[n,2,1]=f[n-1].

关键在a矩阵,根据题目,a矩阵一定是一个2*2的矩阵。很明显,a的第一行是1 1.因为b[n+1,1,1]是第f[n+1]位,而f[n+1]=f
+f[n-1],所以常数项应该是1 1.而一样的,第二行应该是1 0.那么一个矩阵就够造好了。但是想要优化道O(log2 n),还要用快速幂。

快速幂。

用处

将n^m次方从O(m)优化到O(log2 m)

定义

不用说了

用法

先将m转成二进制,在通过二进制来得到n^m.

例如:3^17=[3^(2^1)]x[3^(2^0)]x[3^(2^0)]x[3^(2^0)]x[3^(2^1)]

一共有 log2 n项,每一项都可以用O(1)的方法算出来。具体的自己想。

关于此题

所有的操作都是常数项的,所以,完全可以由普通的递推变成矩阵乘法+快速幂。方法很简单。所以就不讲了。

旋转公式:

我们知道点绕原点逆时针旋转θ度的公式为:



代码

var
u,b:array[1..1000,1..3,1..3] of double;
first,second,third,x,y,px,py:array[1..1000] of double;
a1,z,p:array[1..1000] of longint;
n,i,ge,can,sum,point,j,l:longint;
va:string;
can1,can2,can3:real;
st:array[1..1000] of string;
send:array[1..3,1..3] of double;
function zhuan(p:longint):string;
var
z:longint;
zhuans:string;
begin
zhuan:='';
zhuans:='';
while (p>0) do
begin
z:=p mod 2;
if z=0 then
zhuans:=zhuans+'0'
else
zhuans:=zhuans+'1';
p:=p div 2;
end;
for i:=1 to length(zhuans) do
begin
zhuan:=zhuan+zhuans[length(zhuans)-i+1];
end;
end;
procedure mi(ps,k1:longint);
var
a,pq:array[1..3,1..3] of double;
i,j,k,l:longint;
pss:string;
begin
pss:=zhuan(k1);
a:=u[p[ps]];
for i:=length(pss) downto 1 do
begin
if pss[i]='1' then
begin
fillchar(pq,sizeof(pq),0);
for j:=1 to 3 do
for k:=1 to 3 do
for l:=1 to 3 do
begin
pq[j,k]:=pq[j,k]+send[j,l]*a[l,k];
end;
send:=pq;
end;

fillchar(pq,sizeof(pq),0);
for j:=1 to 3 do
for k:=1 to 3 do
for l:=1 to 3 do
begin
pq[j,k]:=pq[j,k]+a[j,l]*a[l,k];
end;
a:=pq;
end;
end;
procedure dg(k1,q:longint);
var
i,j,l,k,loop,j1:longint;
pq:array[1..3,1..3] of double;
begin
i:=k1;
fillchar(u[q],sizeof(u[q]),0);
for j:=1 to 3 do
u[q,j,j]:=1;
while (i<=q) do
begin
if i=8 then
i:=i;
if (a1[i]<>1) and (a1[i]<>2) then
begin
fillchar(pq,sizeof(pq),0);
for j:=1 to 3 do
for k:=1 to 3 do
for l:=1 to 3 do
begin
pq[j,k]:=pq[j,k]+b[i,j,l]*u[q,l,k];
end;
u[q]:=pq;
end;
if a1[i]=1 then
begin
dg(i+1,p[i]);
loop:=trunc(first[i]);
fillchar(send,sizeof(send),0);
for j:=1 to 3 do
send[j,j]:=1;
mi(i,loop);
fillchar(pq,sizeof(pq),0);
for j:=1 to 3 do
for k:=1 to 3 do
for l:=1 to 3 do
begin
pq[j,k]:=pq[j,k]+send[j,l]*u[q,l,k];
end;
u[q]:=pq;
i:=p[i];

end;
inc(i);
{for j:=1 to 3 do
begin
for k:=1 to 3 do
write(u[q,j,k]:0:1,' ');
writeln;
end;
writeln;   }
end;
end;
begin
assign(input,'transform.in');
assign(output,'transform.out');
reset(input);
rewrite(output);
read(n);
for i:=1 to n do
begin
read(x[i],y[i]);
end;
readln;
while not (eof) do
begin
inc(sum);
readln(st[sum]);
if st[sum][1]='L' then
begin
ge:=6;
va:='';
while (st[sum][ge]='.') or (('0'<=st[sum][ge]) and (st[sum][ge]<='9')) do
begin
va:=va+st[sum][ge];
inc(ge);
end;
val(va,can);
a1[sum]:=1;
first[sum]:=can;
end
else
begin
if st[sum][1]='E' then
begin
a1[sum]:=2;
end
else
begin
if st[sum][1]='T' then
begin
ge:=7;
va:='';
while (st[sum][ge]='.') or (('0'<=st[sum][ge]) and (st[sum][ge]<='9')) or (st[sum][ge]='-') do
begin
va:=va+st[sum][g
d5e2
e];
inc(ge);
end;
val(va,can1);
inc(ge);
va:='';
while (st[sum][ge]='.') or (('0'<=st[sum][ge]) and (st[sum][ge]<='9')) or (st[sum][ge]='-') do
begin
va:=va+st[sum][ge];
inc(ge);
end;
val(va,can2);
a1[sum]:=3;
first[sum]:=can1;
second[sum]:=can2;
end;
if st[sum][1]='S' then
begin
ge:=7;
va:='';
while (st[sum][ge]='.') or (('0'<=st[sum][ge]) and (st[sum][ge]<='9')) or (st[sum][ge]='-') do
begin
va:=va+st[sum][ge];
inc(ge);
end;
val(va,can1);
inc(ge);
va:='';
while (st[sum][ge]='.') or (('0'<=st[sum][ge]) and (st[sum][ge]<='9')) or (st[sum][ge]='-') do
begin
va:=va+st[sum][ge];
inc(ge);
end;
val(va,can2);
a1[sum]:=4;
first[sum]:=can1;
second[sum]:=can2;
end;
if st[sum][1]='R' then
begin
ge:=8;
va:='';
while (st[sum][ge]='.') or (('0'<=st[sum][ge]) and (st[sum][ge]<='9')) or (st[sum][ge]='-') do
begin
va:=va+st[sum][ge];
inc(ge);
end;
val(va,can1);
inc(ge);
va:='';
while (st[sum][ge]='.') or (('0'<=st[sum][ge]) and (st[sum][ge]<='9')) or (st[sum][ge]='-') do
begin
va:=va+st[sum][ge];
inc(ge);
end;
val(va,can2);
inc(ge);
va:='';
while (st[sum][ge]='.') or (('0'<=st[sum][ge]) and (st[sum][ge]<='9')) or (st[sum][ge]='-') do
begin
va:=va+st[sum][ge];
inc(ge);
end;
val(va,can3);
a1[sum]:=5;
first[sum]:=can1;
second[sum]:=can2;
third[sum]:=can3;
end;
end;
end;
end;

for i:=1 to sum do
begin
if (a1[i]=1) or (a1[i]=2) then
begin
b[i,1,1]:=1;
b[i,2,2]:=1;
b[i,3,3]:=1;
end;
if a1[i]=3 then
begin
b[i,1,3]:=first[i];
b[i,1,1]:=1;
b[i,2,3]:=second[i];
b[i,2,2]:=1;
b[i,3,3]:=1;
end;
if a1[i]=4 then
begin
b[i,1,1]:=first[i];
b[i,2,2]:=second[i];
b[i,3,3]:=1;
end;
if a1[i]=5 then
begin
b[i,1,1]:=cos((-first[i])*pi/180);
b[i,1,2]:=-sin((-first[i])*pi/180);
b[i,1,3]:=third[i]*sin((-first[i])*pi/180)-second[i]*cos((-first[i])*pi/180)+second[i];
b[i,2,1]:=sin((-first[i])*pi/180);
b[i,2,2]:=cos((-first[i])*pi/180);
b[i,2,3]:=-third[i]*cos((-first[i])*pi/180)-second[i]*sin((-first[i])*pi/180)+third[i];
b[i,3,3]:=1;
end;
end;
point:=0;
for i:=1 to sum do
begin
if a1[i]=1 then
begin
inc(point);
z[point]:=i;
end;
if a1[i]=2 then
begin
p[z[point]]:=i;
dec(point);
end;
end;
b[sum+1,1,1]:=1;
b[sum+1,2,2]:=1;
b[sum+1,3,3]:=1;
dg(1,sum+1);

for i:=1 to n do
begin
for j:=1 to 3 do
begin
if j=1 then
px[i]:=px[i]+u[sum+1,1,j]*x[i];
if j=2 then
px[i]:=px[i]+u[sum+1,1,j]*y[i];
if j=3 then
px[i]:=px[i]+u[sum+1,1,j];
end;
for j:=1 to 3 do
begin

if j=1 then
py[i]:=py[i]+u[sum+1,2,j]*x[i];
if j=2 then
py[i]:=py[i]+u[sum+1,2,j]*y[i];
if j=3 then
py[i]:=py[i]+u[sum+1,2,j];
end;
end;

for i:=1 to n do
begin
writeln(px[i]:0:4,' ',py[i]:0:4);
end;
close(input);
close(output);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: