蓝桥杯 算法训练 翻转旋转变换

试题 算法训练 翻转旋转变换

资源限制

内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s

问题描述

  现在有一张n行m列的由”o”和”*”字符组成的图案,需要你做若干次翻转和旋转操作,并输出最后的结果.

输入格式

  第一行两个整数n和m

  接下来n行,每行m个字符,表示待变换的图案

  下一行一个整数p表示操作次数

  接下来p行,每行一个整数,表示操作.(1代表水平翻转,2代表垂直翻转,3代表顺时针转90°,4代表逆时针转90°)

输出格式

  输出n行m列(或m行n列)字符,表示变换后的图案

样例输入

4 5

**ooo

**o**

**oo*

**o**

2

2

3

样例输出

****

****

oooo

o*o*

o***

数据规模和约定

  1<=n,m<=100

  0<=p<=1000000

源码:

#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
    int i,j,k,n,m,p,x,g=0,change=0;
    char t[4][102][102];
    char *s[4][102];
    char **q[4];
    scanf("%d%d",&n,&m);
    for(i=0;i<n;i++)
        scanf("%s",&t[0][i]);
    for(k=0;k<3;k++)
    {
        for(i=0;i<m;i++)
        for(j=0;j<n;j++)
            t[k+1][i][j]=t[k][n-j-1][i];
        swap(m,n);
    }
    swap(m,n);
    for(i=0;i<n;i++)
    s[0][i]=t[0][i],s[2][i]=t[2][i];
    for(i=0;i<m;i++)
    s[1][i]=t[1][i],s[3][i]=t[3][i];
    for(i=0;i<4;i++)
    q[i]=s[i];
    scanf("%d",&p);
    while(p--)
    {
        scanf("%d",&x);
        switch(x)
        {
            case 1:swap(q[g],q[(g+2)%4]);
                   for(i=0;i<n/2;i++)
                   swap(q[g][i],q[g][n-1-i]),swap(q[(g+2)%4][i],q[(g+2)%4][n-1-i]);
                   for(i=0;i<m/2;i++)
                   swap(q[(g+1)%4][i],q[(g+1)%4][m-1-i]),swap(q[(g+3)%4][i],q[(g+3)%4][m-1-i]);
                   break;
            case 2:for(i=0;i<n/2;i++)
                   swap(q[g][i],q[g][n-1-i]),swap(q[(g+2)%4][i],q[(g+2)%4][n-1-i]);
                   swap(q[(g+1)%4],q[(g+3)%4]);
                   for(i=0;i<m/2;i++)
                   swap(q[(g+1)%4][i],q[(g+1)%4][m-1-i]),swap(q[(g+3)%4][i],q[(g+3)%4][m-1-i]);
                   break;
            case 3:g=(g+1)%4;break;
            case 4:g=(g+3)%4;break;
        }
        if(g%2!=change%2)
            swap(n,m);
        change=g;
    }
    for(i=0;i<n;i++)
    {
        for(j=0;j<m;j++)
        printf("%c",q[g][i][j]);
        printf("\n");
    }
}

做题过程

这题如果直接循环嵌套一个个交换的话,时间复杂度为1000000*100*100超过10亿会超时的。

之后我想到的是利用指针,在垂直反转时直接交换行指针便可,但是进行水平反转和顺逆旋转并不可以直接交换指针。

在然后我想到的是,这题循环次数特别多,而答案再怎么旋转反转答案也就那几种情况。是不是可以把所有答案都预先计算出来,再用一个变量来记录每一次循环变换后答案的位置。

大体解题思路

如果我们只考虑顺逆时针操作的话,我们可以将旋转0度、90度、180度、270度的矩阵都计算出来,存放到一个三维数组里,再用一个下标来记录每次旋转后的位置,这样不用进行元素交换即可直接输出结果。在此基础上,我们只需要搞清楚在垂直反转和水平反转时,需要对三维数组进行什么操作即可。

过程分析

定义char t[4][102][102]数组

录入原始数据存入t[0][102][102]中;

计算旋转90存入t[1][102][102]中;

计算旋转180存入t[2][102][102]中;

计算旋转270存入t[3][102][102]中;

scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
    scanf("%s",&t[0][i]);//录入原始数据
for(k=0;k<3;k++)
{     
    for(i=0;i<m;i++)
    for(j=0;j<n;j++)
        t[k+1][i][j]=t[k][n-j-1][i];//根据t[0]计算t[1],根据t[1]计算t[2]...
    swap(m,n);//旋转后长宽互换
}
swap(m,n);//最后换回原来的m,n;

定义char *s[4][102] char **q[4];

让数组s指向数组t对应的行首,数组q指向s的行首,通过q来使用这个三维数组。交换数据时便可以直接交换指针,不需要一个个交换元素。

for(i=0;i<n;i++)//旋转0度和180度的行数为n
    s[0][i]=t[0][i],s[2][i]=t[2][i];
for(i=0;i<m;i++)//旋转90度和270度的行数为m
    s[1][i]=t[1][i],s[3][i]=t[3][i];
for(i=0;i<4;i++)
    q[i]=s[i];

定义int g=0;来记录答案的位置从下标0开始。

定义int change=0;来记录上一次g的下标值;如果g下标变化不是二的倍数,则m和n的值需要互换。

当进行顺逆旋转操作时,只需要将g=(g+1)%4或g=(g+3)%4;

顺逆时针旋转90度后进行垂直反转水平反转后进行顺逆时针旋转90度是等价的

所以,如果是垂直反转操作,需要对g和(g+2)%4的位置进行垂直反转操作,(g+1)%4和(g+3)%4位置进行水平反转操作;

垂直反转操作只需要上下行指针交换

水平反转操作将当前位置与加二%4的位置所有元素交换再进行垂直反转操作

scanf("%d",&p);
while(p--)
{
    scanf("%d",&x);
    switch(x)
    {
        case 1:swap(q[g],q[(g+2)%4]);//水平反转 先交换指针实现交换所有元素
               for(i=0;i<n/2;i++)
               swap(q[g][i],q[g][n-1-i]),swap(q[(g+2)%4][i],q[(g+2)%4][n-1-i]);//再垂直反转
               for(i=0;i<m/2;i++)
               swap(q[(g+1)%4][i],q[(g+1)%4][m-1-i]),swap(q[(g+3)%4][i],q[(g+3)%4][m-1-i]);//垂直反转
               break;
        case 2:for(i=0;i<n/2;i++)
               swap(q[g][i],q[g][n-1-i]),swap(q[(g+2)%4][i],q[(g+2)%4][n-1-i]);//垂直反转
               swap(q[(g+1)%4],q[(g+3)%4]);//水平反转 先交换指针实现交换所有元素
               for(i=0;i<m/2;i++)
               swap(q[(g+1)%4][i],q[(g+1)%4][m-1-i]),swap(q[(g+3)%4][i],q[(g+3)%4][m-1-i]);//再垂直反转
               break;
        case 3:g=(g+1)%4;break;
        case 4:g=(g+3)%4;break;
    }
    if(g%2!=change%2)
        swap(n,m);//如果变化g的变化不是二的倍数就行列交换
    change=g;
}

总结:

  1. 二级指针的使用,通过交换指针来降低时间复杂度。

  1. 用取余实现循环。

  1. 对于答案种类少而一直循环运算的问题,看看是否可以预先算出答案,用下标记录答案的位置,简化运算。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值