[week11]必做题11-2

题意

蒜头君的班级里有 n^2 个同学,现在全班同学已经排列成一个n∗n 的方阵,但是老师却临时给出了一组新的列队方案

为了方便列队,所以老师只关注这个方阵中同学的性别,不看具体的人是谁

这里我们用0 表示男生,用1 表示女生

现在蒜头君告诉你同学们已经排好的方阵是什么样的,再告诉你老师希望的方阵是什么样的

他想知道同学们已经列好的方阵能否通过顺时针旋转变成老师希望的方阵

不需要旋转则输出 0
顺时针旋转 90° 则输出 1
顺时针旋转 180° 则输出 2
顺时针旋转 270° 则输出 3

若不满足以上四种情况则输出 −1

若满足多种情况,则输出较小的数字

Input

第一行为一个整数 n

接下来的 n 行同学们已经列好的 01 方阵;

再接下来的 n 行表示老师希望的的 01 方阵。

Output

输出仅有一行,该行只有一个整数,如题所示。

输入样例

4
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0
0 1 0 0
0 0 0 0
0 0 0 0

输出样例

1

提示

对于 100% 的数据中,1≤n≤20

输出时每行末尾的多余空格,不影响答案正确性


分析

简单的规律判断题


  • 题目分析

对一个矩阵连续90度旋转2次、3次就相当于对该矩阵旋转了180度和270度。因此只需要找到顺时针翻转90度的规律,再对翻转后的矩阵重复该操作即可实现旋转不同度数。

若当前旋转操作结束后,仍然需要旋转,则旋转次数+1,继续调用。当出现第4次调用时,即证明不能转换。

  • 顺时针旋转90度规律
    在这里插入图片描述

由图可知:

  1. 旋转前 列 = 旋转后 行
  2. 旋转前 行 + 旋转后 列 = n + 1 (n为边长)

  • 问题 & 优化

  • 优化

为了简单优化时间复杂度,做出以下简单的优化:

  1. 在输入初始矩阵和目标矩阵的过程中,分别用两个一维数组记录两个矩阵中每一行的元素和,在比较初始矩阵和目标矩阵的过程中,简化不等情况下的时间复杂度。
    输入结束后,对两个一维数组进行判断,如果出现某一行的元素和不等,说明初始矩阵和目标矩阵一定不等,需要转换;否则,对两个矩阵中对应相同行中的所有元素依次遍历比较,若出现不等,说明两个矩阵不等,需要转换;反之,若初始矩阵和目标矩阵相等,时间复杂度最差,为n^2。

  2. 在转换过程中,就对每个当前得到的旋转后元素与目标矩阵中对应位置进行比较。

  3. 为了省去将旋转后矩阵复制到存储初始矩阵中的n^2次操作,将旋转函数设置两个二维数组传入参数,分别对应存储矩阵和待旋转矩阵。
    可以发现,在奇数次旋转中,新建的中间矩阵用来存储旋转结果;偶数次旋转中,就可以用初始矩阵来存储新的旋转后结果。利用该规律进行对应调用

  • 问题

在声明数组时,不能用变量作为初始化参数。


总结

  1. 数组传参我永远都搞不清楚🐒

代码

//
//  main.cpp
//  lab2
//
//

#include <iostream>
using namespace std;

int origin[21][21],obj[21][21],mid[21][21];
int n = 0,ans = 0;
bool judge = true;

void change(int b[][21],int a[][21])       //顺时针旋转90
{
    for( int i = 1 ; i <= n ; i++ )         //旋转
        for( int j = 1 ; j <= n ; j++ )
        {
            b[i][j] = a[n + 1 - j][i];
            
            if( b[i][j] != obj[i][j] )            //判断旋转后的矩阵与目标矩阵是否相等
                judge = false;
        }
}

int main()
{
    ios::sync_with_stdio(false);
    
    cin>>n;
    
    int res1[21] = {0};
    int res2[21] = {0};        //记录两个矩阵中每一行的和
    
    for( int i = 1 ; i <= n ; i++ )         //初始状态
        for( int j = 1 ; j <= n ; j++ )
        {
            cin>>origin[i][j];
            res1[i] += origin[i][j];
        }
    
    for( int i = 1 ; i <= n ; i++ )         //理想状态
        for( int j = 1 ; j <= n ; j++ )
        {
            cin>>obj[i][j];
            res2[i] += obj[i][j];
        }


    for( int i = 1 ; i <= n ; i++ )     //遍历和数组
    {
        if( res1[n] != res2[n] )        //若出现不等,则一定需要旋转
        {
            judge = false;
            break;
        }
        
        for( int j = 1 ; j <= n ; j++ )     //若相等,则遍历两个矩阵中的第i行中所有元素
        {
            if( origin[i][j] != obj[i][j] )         //若出现不等,则一定需要遍历
            {
                judge = false;
                break;
            }
        }
    }
    
    if( judge )                 //若初始矩阵相同,直接输出0
        cout<<0<<endl;
    else
    {

        do                          //否则进行循环旋转
        {
            ans++;                  //第ans次旋转
            if( ans >= 4 )          //若当前要旋转第4次,直接退出
                break;
            
            judge = true;

            if( ans % 2 == 1 )          //奇数次旋转
                change(mid,origin);               //mid数组存储结果
            else                        //偶数次旋转
                change(origin, mid);                //origin数组存储结果
            
        }while( !judge );           //判断
        
        if( ans < 4 )               //若小于4,直接输出答案
            cout<<ans<<endl;
        else                            //否则无法实现
            cout<<-1<<endl;
    }

    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天翊藉君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值