JZOJ 3498【NOIP2013模拟联考14】图形变换

题目大意:

给你N个点的坐标。现有一些操作,求执行完所有操作后这些点的坐标。
操作1:让这些点的坐标加上一些数;
操作2:让这些点的坐标乘上一些数;
操作3:让这些点绕着一个中心点顺时针旋转θ角度;
操作4:给定一个循环体和循环次数,循环执行循环体中的操作;(循环可以嵌套)

这里讲讲操作3怎么处理。
设x[i],y[i]为点的坐标。xx,yy为旋转中心的坐标。x1,y1为旋转后的点的坐标。

x1=(x[i]-xx)*cos(angle)-(y[i]-yy)*sin(angle)+xx;

y1=(y[i]-yy)*cos(angle)+(x[i]-xx)*sin(angle)+yy;
注意angle是弧度角。

模拟操作能得30分,AC不了主要是操作4循坏太慢。
怎么优化?
我们要思考怎样避免每次都模拟循环,一个直接的想法就是把循环作为一个整体保存下来,避免重复运行。
如何保存中间过程,我们注意到题目中的变换其实都是对于两个变量的线性递推,完全可以用矩阵来实现,这样根据矩阵的结合律,就可以把一堆变换作为整体保存。而循环多次就相当于把这个代表变换的矩阵乘几次,加上快速幂就能AC了。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define N 110
#define M 1010
#define pi M_PI
#define rad(x) x*pi/180
typedef double matrix[4][4];
using namespace std;
struct Operation
{
       double x1,y1,angle;
       int time,type;
}a[M];
int n,m,top,stack[M],end[M];
double x[N],y[N];
matrix H;
char ch;
void mul(matrix a,matrix b)
{
     matrix c;
     memset(c,0,sizeof(c));
     fo(k,1,3)
         fo(i,1,3)
             fo(j,1,3)
                 c[i][j]+=a[i][k]*b[k][j];
     memcpy(a,c,sizeof(c));
}
void qmi(matrix &a,int x)
{
     matrix c;
     memset(c,0,sizeof(c));
     fo(i,1,3) c[i][i]=1;
     while(x>0)
     {
               if(x&1==1) mul(c,a);
               mul(a,a);
               x>>=1;
     }
     memcpy(a,c,sizeof(c));
}
void dg(int st,int en)
{
     if(st>en) return;
     matrix F,G;
     memset(F,0,sizeof(F));
     fo(i,1,3) F[i][i]=1;
     fo(i,st,en)
     {
                memset(G,0,sizeof(G));
                if(a[i].type==1)
                {
                    G[1][1]=1;
                    G[2][2]=1;
                    G[3][1]=a[i].x1;
                    G[3][2]=a[i].y1;
                    G[3][3]=1;
                    mul(F,G);
                }
                if(a[i].type==2)
                {
                    G[1][1]=a[i].x1;
                    G[2][2]=a[i].y1;
                    G[3][3]=1;
                    mul(F,G);
                }
                if(a[i].type==3)
                {
                    a[i].angle=360-a[i].angle;
                    double s1=cos(rad(a[i].angle)),s2=sin(rad(a[i].angle));
                    G[1][1]=s1;
                    G[1][2]=s2;
                    G[2][1]=-s2;
                    G[2][2]=s1;
                    G[3][1]=s2*a[i].y1-s1*a[i].x1+a[i].x1;
                    G[3][2]=-s1*a[i].y1-s2*a[i].x1+a[i].y1;
                    G[3][3]=1;
                    mul(F,G);
                }
                if(a[i].type==4)
                {
                    dg(i+1,end[i]-1);
                    qmi(H,a[i].time);
                    mul(F,H);
                    i=end[i];
                }
     }
     memcpy(H,F,sizeof(F));
}
int main()
{
    freopen("transform.in","r",stdin);
    freopen("transform.out","w",stdout);
    cin>>n;
    fo(i,1,n) scanf("%lf%lf\n",&x[i],&y[i]);
    while(scanf("%c",&ch)!=EOF)
    {
        m++;
        if(ch=='T') a[m].type=1,scanf("rans(%lf,%lf)\n",&a[m].x1,&a[m].y1);
        if(ch=='S') a[m].type=2,scanf("cale(%lf,%lf)\n",&a[m].x1,&a[m].y1);
        if(ch=='R') a[m].type=3,scanf("otate(%lf,%lf,%lf)\n",&a[m].angle,&a[m].x1,&a[m].y1);
        if(ch=='L') a[m].type=4,scanf("oop(%d)\n",&a[m].time);
        if(ch=='E') a[m].type=5,scanf("nd\n");
    }
    int top=0;
    fo(i,1,m)
        if(a[i].type==4) stack[++top]=i;
        else
        if(a[i].type==5) end[stack[top--]]=i;
    dg(1,m);
    fo(i,1,n)
    {
             matrix F;
             memset(F,0,sizeof(F));
             F[1][1]=x[i],F[1][2]=y[i],F[1][3]=1;
             mul(F,H);
             printf("%.4lf %.4lf\n",F[1][1],F[1][2]);
    }
    fclose(stdin);fclose(stdout);
}

你可能感兴趣的:(题解,图形,矩阵乘法)