蒟蒻第一次写题解,求大佬勿喷,完整代码请扒拉到最底下。
解题要求:只需要会基础的判断,循环,数组,指针,函数即可
首先是找规律
题目中很明显需要二维数组来存储矩阵,然后要求我们进行坐标变换,一一对应比较,最终判断是哪种情况,但是光是这个坐标变换的数学规律就需要思考挺久,愣是在纸上算了半天没算出来,但是我岂能被区区困难打倒,于是我选择了放弃参考大佬,得到了各种情况坐标变换的规律。
其次是顺利输入、读取和存储矩阵元素
说实话这个对于我这个菜鸡来说也是挺麻烦的一件事
首先用char定义两个二维数组,分别存储两个矩阵。
char mtx[11][11];//原始矩阵
char tmtx[11][11];//变换后的矩阵
常见问题:
为啥不用int、string?
因为存储的元素单位是字符。
输入是连续的字符/输入里边有回车该怎么输入?
用两个for循环逐个输入
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> mtx[i][j];
}
}
输入第一个字符后随着循环继续进行,cin会自动进入下一个等待输入,至于回车或者空格,甚至只用一行全部输入完全不会影响数据存入矩阵的顺序,因为cin是从输入流中读取数据,对于字符串输入,cin默认使用空白字符(空格、制表符和回车等)作为分隔符,这意味着cin在遇到空格或回车时会将输入截断,并将你输入的内容存入数组。
完成这些之后,你可以自己尝试输出一下两个矩阵,检查自己是否正确输入和存储,这里我就不写了,把上边的cin改成cout就OK了。
接下来就是将坐标变换规律用代码表示出来
这里就需要用到函数和指针的知识了。
使用函数可以让我们的代码更加简洁,更加模块化,因为重复的部分只需要写一小行调用就完了,纠错修改也只需要修改一处。
使用指针是因为我们需要修改传入函数的值,所以需要用到指针传入地址。
以旋转90度举个栗子:
void turn90(int *i,int *j)//顺时针旋转90度
{
int vessel;
vessel = *j;
*j = n - *i + 1;
*i = vessel;
}
turn90(&k, &l);//调用函数
然后来到第二个关键部分:如何判断
这里我们需要判断的是,转换后的矩阵的矩阵和题目要求的矩阵是以何种方法转换的?
这里我为每一种情况建立了一个标号,标号的数字就代表相应的情况,也就是我最终输出的东西:
int seq[9] = {1,2,3,4,5,5,5,6,7};
//其中5是三种情况的组合,只要满足一个组合输出的都是5
//如果只定义一个5的话,那么一旦其中一个情况被否定,更改标号之后,剩下另外两个情况就无法继续讨论
//所以组合的三种情况都各自对应一个5,这样既可以分开讨论,输出的时候也保证都是5
那我是如何具体实现标记和判断功能的呢?还是拿旋转90度举个栗子:
for (int i = 1; i <= n; i++)//遍历矩阵
{
for (int j = 1; j <= n; j++)
{
if (seq[0] == 1)
//首先对标号进行判断,若标号未被更改,则进入下边的代码
//否则直接终止剩下坐标转换,这样就不需要把所有坐标转换完再进行比较了
{
k = i;
l = j;
turn90(&k, &l);//调用函数,传入地址更改实参,转换坐标
if (tmtx[k][l] != mtx[i][j])//如果发现和转换后的矩阵元素对不上
{
seq[0] = 10;//则更改标号,之后就不需要再次进行坐标变换了
//否则就继续逐个对比
}
}
}
}
所以这样每种情况都试一遍的情况下,标号可能会变这样:
int seq[9] = {10,10,10,10,5,10,10,6,7};
此时5、6代表着可以通过镜像翻转达到,同时转换后的图像和原图像一样,剩下的10代表着该方法被否决了,此时我们利用sort函数进行一次升序排序:
int seq[9] = {5,6,7,10,10,10,10,10,10};
那么第一个元素就是5,我们只需要输出第一个元素,就能达到题目“如果有多种可用的转换方法,请选择序号最小的那个”的要求。
最后一个是7(代表无法用以上方法得到新图案)的原因是:
如果前边有方法满足条件,那么这个数会小于7,7会排在它后边不会输出。
如果都没有条件满足,那么其他数都是10,都会大于7,这样7就会排在第一个被输出了,这样就减少了一次判断。
完整代码
#include<iostream>
#include<algorithm>
using namespace std;
char mtx[11][11];//原始矩阵
char tmtx[11][11];//变换后的矩阵
int seq[9] = {1,2,3,4,5,5,5,6,7};
//存储每种情况的标号,也是最后要输出的东西
//如果对比过程中发现此情况不满足,就更改标号为10(大于7就行)
//通过sort函数升序排序,将标号为10的元素挪到后边,将最小的元素挪到最前边
//然后输出第一个元素seq[0]
//即满足了题目的要求:“如果有多种可用的转换方法,请选择序号最小的那个”
//其中5是三种情况的组合,只要满足一个组合输出的都是5
//如果只定义一个5的话,那么一旦其中一个情况被否定,更改标号之后,剩下另外两个情况就无法继续讨论
//所以组合的三种情况都各自对应一个5,这样既可以分开讨论,输出的时候也保证都是5
//最后一个是7(代表无法用以上方法得到新图案)的原因是,
//如果前边有方法满足条件,那么这个数会小于7,7会排在它后边不会输出
//如果都没有条件满足,那么其他数都是10,都会大于7,这样7就会排在第一个被输出了
//这样就减少了一次判断
int n;
void turn90(int *i,int *j)//顺时针翻转90度
{
int vessel;
vessel = *j;
*j = n - *i + 1;//坐标变换公式,参考的大佬的呜呜呜
*i = vessel;
}
void turn180(int* i, int* j)//顺时针翻转180度
{
int vessel1;
vessel1 = *j;
*j = n - *i + 1;
*i = vessel1;
int vessel2;
vessel2 = *j;
*j = n - *i + 1;
*i = vessel2;//执行两次翻转90度就是翻转180度
}
void turn270(int* i, int* j)//顺时针翻转270度
{
int vessel1;
vessel1 = *j;
*j = n - *i + 1;
*i = vessel1;
int vessel2;
vessel2 = *j;
*j = n - *i + 1;
*i = vessel2;
int vessel3;
vessel3 = *j;
*j = n - *i + 1;
*i = vessel3;//执行三次翻转90度就是翻转270度
}
void mirror(int* i, int* j)//水平方向沿铅垂线翻转
{
*j = n - *j + 1;//还是参考大佬的公式
}
void combine1(int* i, int* j)//组合1
{
*j = n - *j + 1;//镜像翻转
int vessel;
vessel = *j;
*j = n - *i + 1;
*i = vessel;//旋转90度
}
void combine2(int* i, int* j)//组合2
{
*j = n - *j + 1;//镜像翻转
int vessel1;
vessel1 = *j;
*j = n - *i + 1;
*i = vessel1;
int vessel2;
vessel2 = *j;
*j = n - *i + 1;
*i = vessel2;//旋转180度
}
void combine3(int* i, int* j)//组合3
{
*j = n - *j + 1;//镜像翻转
int vessel1;
vessel1 = *j;
*j = n - *i + 1;
*i = vessel1;
int vessel2;
vessel2 = *j;
*j = n - *i + 1;
*i = vessel2;
int vessel3;
vessel3 = *j;
*j = n - *i + 1;
*i = vessel3;//旋转270度
}
int main()
{
int k = 0, l = 0;//用于暂存i,j,这样就不会更改i,j的值
cin >> n;
for (int i = 1; i <= n; i++)//存入原始矩阵,注意是从1开始的,这样才能对应公式
//如果是从0开始则公式也要做相应修改,之前就在这里纠结半天
{
for (int j = 1; j <= n; j++)
{
cin >> mtx[i][j];
}
}
for (int i = 1; i <= n; i++)//存入改变后的矩阵,也是从1开始
{
for (int j = 1; j <= n; j++)
{
cin >> tmtx[i][j];
}
}
for (int i = 1; i <= n; i++)//开始转换原始矩阵,在转换的同时和第二个矩阵逐个比较,记得从1开始!!
{
for (int j = 1; j <= n; j++)
{
if (seq[0] == 1)//旋转90度
//对标号进行判断,若标号未被更改,则继续转换
//否则直接终止剩下坐标转换,就不需要把所有坐标转换完再进行比较了
{
k = i;
l = j;
turn90(&k, &l);//调用函数,传入地址更改实参,转换坐标
if (tmtx[k][l] != mtx[i][j])//如果发现和转换后的矩阵元素对不上
{
seq[0] = 10;//则更改标号,之后就不需要再次进行坐标变换了
}
}
if (seq[1] == 2)//旋转180度
{
k = i;
l = j;
turn180(&k, &l);
if (tmtx[k][l] != mtx[i][j])
{
seq[1] = 10;
}
}
if (seq[2] == 3)//旋转270度
{
k = i;
l = j;
turn270(&k, &l);
if (tmtx[k][l] != mtx[i][j])
{
seq[2] = 10;
}
}
if (seq[3] == 4)//镜像旋转
{
k = i;
l = j;
mirror(&k, &l);
if (tmtx[k][l] != mtx[i][j])
{
seq[3] = 10;
}
}
if (seq[4] == 5)//组合1
{
k = i;
l = j;
combine1(&k, &l);
if (tmtx[k][l] != mtx[i][j])
{
seq[4] = 10;
}
}
if (seq[5] == 5)//组合2
{
k = i;
l = j;
combine2(&k, &l);
if (tmtx[k][l] != mtx[i][j])
{
seq[5] = 10;
}
}
if (seq[6] == 5)//组合3
{
k = i;
l = j;
combine3(&k, &l);
if (tmtx[k][l] != mtx[i][j])
{
seq[6] = 10;
}
}
if (seq[7] == 6)//一毛一样
{
if (tmtx[i][j] != mtx[i][j])
{
seq[7] = 10;
}
}
}
}
sort(seq, seq + 9);//利用sort函数升序排序,选出数组中最小的数,
cout << seq[0];//最终输出最小的结果
return 0;
}