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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sulvshuo/article/details/78151205

【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.

猜你喜欢

转载自blog.csdn.net/sulvshuo/article/details/78151205