【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.
- 【NOIP2013模拟联考14】图形变换(transform)
- 【NOIP2013模拟联考14】图形变换(transform)
- JZOJsenior3498.【NOIP2013模拟联考14】图形变换(transform)
- [jzoj]3498. 【NOIP2013模拟联考14】图形变换(transform) (计算几何+矩阵乘法)
- JZOJ 3498【NOIP2013模拟联考14】图形变换
- 【NOIP2013模拟联考13】线段
- 【NOIP2013模拟联考7】数列
- 【NOIP2013模拟联考5】军训
- 【NOIP2013模拟联考6】选课
- 【NOIP2013模拟联考7】OSU
- 【NOIP2013模拟联考5】军训(training)
- 【NOIP2013模拟联考6】选课(select)
- 【NOIP2013模拟联考5】军训(training) 题解
- NOIP2013模拟联考5】军训(training)
- 【NOIP2013模拟联考2】摘取作物(pick)
- 【NOIP2013模拟联考3】山峰(summits)
- 【NOIP2013模拟联考15】人类基因组(genes)
- 【NOIP2013模拟联考10】独立集(bubble)
- 51nod 1837 砝码称重 (规律)
- HPU 周练一
- Linux Shell经典实例解析--Oracle启动脚本(上)
- 【前端前沿看点】weex和react native的原生开发之争——对比分析
- 基于JavaScript的前端常用排序算法实现(1)
- 【NOIP2013模拟联考14】图形变换(transform)
- python的os.path模块常用
- 2457: [BeiJing2011]双端队列
- Linux Shell经典实例解析--Oracle启动脚本(下)
- 拓扑排序(Topological Sorting)
- java泛型通配符
- 关联容器(set & multiset & Map& multimap)
- unity导入/播放视频问题
- 十四讲重新过一遍,今天进度到了第七讲,139页ORB特征点提取程序的部分参数解释如下