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

来源:互联网 发布:淘宝店铺女装货源 编辑:程序博客网 时间:2024/05/23 12:11

【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判断,只要你输出的数值与标准答案误差不能超过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[n],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[n]+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][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]:=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.
阅读全文
0 0