模拟 poj 3106 Flip and Turn

题目链接:

http://poj.org/problem?id=3106

题目大意:

有一个m*n的矩阵,有10种操作,给一个操作串,求最后的矩阵。

操作'1'  :沿主对角线翻转 行列交换

操作‘2’:沿副对角线翻转  行列交换

操作‘H':沿水平方向翻转 

操作’V‘:沿竖直方向翻转

操作’A‘:顺时针旋转90度,’B':顺时针旋转180度,‘C'顺时针旋转270度。除180度行列不交换外,其他两种行列交换

操作’X‘:逆时针旋转90度,’Y‘:逆时针旋转180度,’Z‘逆时针旋转270度。除180度行列不交换外,其他两种行列交换

操作字符串最多有100000个,如果每一个操作都对矩阵的每个元素进行,肯定会超时。所以就会想到,如果把所有的操作都统一处理成简单的几种操作,最后等价处理后,再对矩阵进行一次操作,就会很简单,也不会超时。

关键是找等价关系,并且能够用数学语言等价描述。我的想法是,将十种操作都对应成H,V,和A三种操作,对每一个操作都转化成HVA的方式。

很显然有如下关系:H和V最多出现一个,因为H+V(先水平翻转再竖直翻转)=V+H(先竖直翻转再水平翻转)=A*2(顺时针旋转90度两次)。H+H=0(先水平翻转再水平翻转等于本身)同理:V+V=0 所以最后的结果集只可能是00a,01a,10a(a表示顺时针旋转90度的次数)

对于操作’1‘:等价于先逆时针旋转90度再H一次<=>先H再顺时针旋转90度一次。 XH=HA

对于操作’2‘:等价于先顺时针旋转90度再H一次<=>先H再逆时针旋转90度一次。AH=HX

对于操作’H‘:直接和前面的等价关系**a中的a(顺时针旋转90度的次数)组合成AH=HX,一直递推到V,a次顺时针全部转化为a次顺时针。

对于操作’V‘:XV=VA=AH=HX

对于’A‘,’B‘,’C‘直接加到顺时针次数上。

对于’X‘,’Y‘,’Z‘直接减到顺时针次数上。

所以用三个变量hh,vv,shun表示水平翻转次数,竖直翻转次数,顺时针旋转次数,注意是有顺序的。

XV=AH=HX AV=XH=HA

扫描每个操作,等价处理,不满足该顺序的借助等价关系改变顺序,保持该顺序不变。

详细解释代码:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 330
#define M 110000

char a[Maxn][Maxn],b[Maxn][Maxn];
char ord[M];
int m,n;

void funh() //执行水平操作
{
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            b[m-i+1][j]=a[i][j];
    memcpy(a,b,sizeof(b));
}
void funv() //执行竖直操作
{
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            b[i][n-j+1]=a[i][j];
    memcpy(a,b,sizeof(b));
}
void funa() //执行顺时针旋转90度操作
{
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            b[j][m-i+1]=a[i][j];
    swap(n,m);
    memcpy(a,b,sizeof(b));
}

int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);

   while(~scanf("%d%d",&m,&n))
   {
       for(int i=1;i<=m;i++)
            scanf("%s",a[i]+1);
       scanf("%s",ord);
       int hh=0,ss=0;  //hh表示水平翻转次数,ss表示竖直翻转次数
       int shu=0,len=strlen(ord); //shu表示顺时针旋转次数
       int flag=0;

       for(int i=0;i<len;i++)
       {
           switch(ord[i])
           {
               case '1':
               {
                   flag^=1; //行列交换
                   //由 XH=HA 和 AH=HX
                   if(shu)  //如果之前有顺时针旋转
                       shu=(-shu+4)%4; //顺时针全部转化为逆时针
                   shu=(shu+1)%4; //最后还有个A
                   if(hh) //H+H=0
                     hh=0;
                   else if(ss) //V+H=AA
                   {
                       hh=0;
                       ss=0;
                       shu=(shu+2)%4;
                   }
                   else  //H=0 V=0时H=1
                      hh++;

               }
               break;
               case '2':
               {
                   flag^=1; //HX
                   if(shu)
                       shu=(-shu+4)%4;
                   shu=(shu-1+4)%4; //最后有一个X
                   if(hh)
                       hh=0;
                   else if(ss)
                   {
                       hh=0;
                       ss=0;
                       shu=(shu+2)%4;
                   }
                   else
                     hh++;
               }
               break;
               case 'V':
               {
                   if(shu) //AV=XH=HA
                   {
                       shu=(-(shu-1)+4)%4;
                       shu=(shu+1)%4; //最后有一个A
                       if(ss)
                       {
                           ss=0;
                           hh=0;
                           shu=(shu+2)%4;
                       }
                       else if(hh)
                          hh=0;
                       else
                          hh++;
                      break;
                   }
                  if(ss)
                  {
                      ss=0;
                      hh=0;
                      //shu=(shu+2)%4;
                  }
                  else if(hh)
                  {
                      ss=0;
                      hh=0;
                      shu=(shu+2)%4;
                  }
                  else
                     ss++; //如果一个H和V都没有,ss++

               }
               break;
               case 'H':
               {
                   if(shu)
                       shu=(4-shu)%4;
                   if(ss)
                   {
                       ss=0;
                       hh=0;
                       shu=(shu+2)%4;
                   }
                   else if(hh)
                       hh=0;
                   else
                      hh++;
               }
               break;
               case 'A':
                 shu=(shu+1)%4;flag^=1;break;
               case 'B':
                  shu=(shu+2)%4;break;
               case 'C':
                  flag^=1;shu=(shu+3)%4;break;
               case 'X':
                  flag^=1;shu=(shu-1+4)%4;break;
               case 'Y':
                  shu=(shu-2+4)%4;break;
               case 'Z':
                  flag^=1;shu=(shu-3+4)%4;break;
           }

       }
       //printf("flag:%d hh:%d ss:%d shu:%d\n",flag,hh,ss,shu);

       if(hh) //注意执行顺序 H V a
           funh();
       else if(ss)
            funv();
       if(shu) //顺时针旋转次数
       {
           while(shu--)
               funa();
       }
       /*if(flag)
           swap(n,m);*/
       printf("%d %d\n",m,n);
       for(int i=1;i<=m;i++)
       {
           for(int j=1;j<=n;j++)
                printf("%c",a[i][j]);
          putchar('\n');
       }
   }

   return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值