蛇形矩阵和圣诞树思路分析
文章目录
前言
哈喽,各位小伙伴们大家好!今天小编给大家带来蛇形矩阵和超级圣诞树两道题目的思路分析和讲解。这两道题都需要经过观察规律进行分析才能解题。可以提升我们的思维和观察能力。话不多说,咱们进入主题!
1.蛇形矩阵
1.1题目
相信很多小伙伴可能和我一样,第一次接触题目时看不懂题目意思(什么是蛇形矩阵)。没事,小编来给大家讲解题目意思(怎么个蛇形法)。
1.2题目解释
大家可以看到,从1开始跟着箭头走,就会发现数字在不断加1。并且箭头路径像蛇走路时一样,呈现s型路径。这就是蛇形矩阵啦。
1.3思路分析
为了方便大家理解,我画了个思路图。以4*4的矩阵为例,大家可以看到箭头有四种移动方向。每当i=0或j=0是,箭头就会进行一次掉头。每次掉头我们将它拆分为刹车和转弯。刹车只要向下或向右移动一次,而转弯则向右上方或左下方移动直到下一次掉头。但这只是上半部分,到了下半部分,以10为例本应向下刹车却向右,13本应向右刹车却向下,所以对角线后半部分我们需要将刹车方向对调。为了判断上下部分,我们可以在每次刹车和转弯后对i=n-1和j=n-1记录,记录达到两次蛇就进入下半部分啦。
1.4上半部分
我们可以先创建一个足够大的二维数组存放数据,在创建i和j两个变量来表示此时蛇头的位置(箭头移动到哪)。之后用if语句判断刹车,再用while循环控制转弯直线。同时用count变量记录次数。
int n = 0;
scanf("%d", &n);
int a[20][20] = { 0 };//创建足够的的数组存放数据;
int count = 0;
int i = 0;//代表行
int j = 0;//代表列
a[0][0] = 1;//先给第一个位置(蛇尾)赋值
while (count != 2)//控制上部分的循环次数
{
if (0 == i || 0 == i && 0 == j)//判断掉头方向(第一个位置处于a[0][0]但是右转)
{
a[i][j+1] = a[i][j] + 1;//赋值(原位置数加一)
j++;//向右刹车
if (n - 1 == i || n - 1 == j)
count++;//统计对角线顶点次数
while (j != 0)//转弯部分
{
a[i+1][j-1] = a[i][j] + 1;//赋值(原位置数加一)
j--;
i++;//向左下移动
}
}
else if (0 == j)//判断掉头方向
{
a[i + 1][j] = a[i][j] + 1;//赋值(原位置数加一)
i++;//向下刹车
if (n - 1 == i || n - 1 == j)
count++;//统计对角线顶点次数
while (i != 0)//转弯部分
{
a[i - 1][j + 1] = a[i][j] + 1;//赋值(原位置数加一)
i--;
j++;//向右上移动
}
}
if (n - 1 == i || n - 1 == j)
count++;//统计对角线顶点次数
1.5下半部分
下半部分只需要修改刹车方向即可,同时无需再记录次数,其他与上半部分一样。`
while (2 == count&&a[n-1][n-1]==0)//进入下部分并且控制结束
{
if (n - 1 == i)//判断掉头方向
{
a[i][j+1] = a[i][j] + 1;//赋值(原位置数加一)
j++;//向右刹车
while (n - 1 != j)//转弯部分
{
a[i-1][j+1] = a[i][j] + 1;//赋值(原位置数加一)
j++;
i--;//向右上移动
}
}
else if (n - 1 == j)//判断掉头方向
{
a[i+1][j] = a[i][j] + 1;//赋值(原位置数加一)
i++;//向下刹车
while (n - 1 != i)//转弯部分
{
a[i+1][j-1] = a[i][j] + 1;//赋值(原位置数加一)
i++;
j--;//向左下移动
}
}
}
1.6遍历打印
最后只需用两个for循环遍历数组,再用if判断是否赋值,最后打印即可。为了美观,我们可以采用%3d打印。
for (int i = 0; i < n; i++)//遍历数组
{
for (int j = 0; j < n; j++)
{
if (a[i][j] != 0)//判断输出
printf("%3d ", a[i][j]); //每个数据占三个空格,不足三位数往前填空格
}
printf("\n");//换行
}
2.超级圣诞树
2.1题目
大家可以看到圣诞树分为两部分,上面由三角形构成的我们称为树的主体,下面的直线部分称为树干。
2.2思路分析
不难看出下面两个三角形其实就是上面的三角形复制过来的,只要我们找到复制规律就可以解出题目了。仔细观察就会发现每个星号的复制行移动都是原来三角形占的行数,列移动是原来三角形占的列数除二(取整)加一。对称点左右行和列移动就可已完成复制。
2.3扫描标记
我们可以先创建一个足够大的二维数组。之后计算好n圣诞树占的行数和列数,先给树干部分和第一个三角形做标记(标记为1)。随后用for循环控制复制次数和扫描标记点,根据每个标记点的位置,进行左右标记,直到循环结束。
int n = 0;
scanf("%d", &n);//接收数据
int a[100][100] = { 0 };
int s = 5;//每个三角形占五列
int k = pow(2, n - 1);//计算(每次复制行数变为原来的两倍)
int r = n + (3 * k);//树干行数加树主体2行数(n是树干占行数,3是每个三角形占行数)
int m = 5;
for (int i = 0; i < n - 1; i++)
{
s = (2 * s) + 1;//计算复制完后的图形的列数从而确定顶点所在列
}
for (int i = r-n; i <r ; i++)
{
a[i][s / 2] = 1;//给树干部分做标记
}
a[0][(s / 2) ] = 1;
a[1][(s / 2)-1] = 1;
a[1][(s / 2) + 1] = 1;
a[2][(s / 2)] = 1;
a[2][(s / 2) -2] = 1;
a[2][(s / 2) + 2] = 1;//先给第一个三角形标记
for (int i = 0; i < n - 1; i++)
{
int p = 0;
int m = 5;
for (int j = 0; j < i; j++)
{
p = m;
m = (2 * p) + 1;//计算扫描区列数
}
int k = pow(2, i);
int r = (3 * k);//计算扫描区的行数
for (int g = 0; g < r; g++)//扫描行
{
for (int q = 0; q < 100; q++)//扫描列
{
if (a[g][q] == 1)//判断是否为标记点
{
a[g +r][q - ((m / 2) + 1)] = 1;//复制左边三角形
a[g +r][q + ((m / 2) + 1)] = 1;//复制右边三角形
}
}
}
}
2.4遍历打印
完成全部标记后,我们可以两个for循环遍历数组,if判断是否为标记点,对标记点打印星号即可。这里大家如果想增加点趣味性或给某些重要的人看的话,推荐大家用sleep打印。注意sleep需要包含头文件include<Windows.h>。
for (int i = 0; i < 100; i++)//遍历数组打印
{
for (int j = 0; j < 100; j++)
{
if (a[i][j] == 0)//打印空格
printf(" ");
else
{
printf("*");//打印星号
Sleep(1000);//睡眠打印(延迟打印,可以看到过程,更有氛围感!)
}
}
printf("\n");//换行
}
3.源码
3.1蛇形矩阵
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int a[20][20] = { 0 };//创建足够的的数组存放数据;
int count = 0;
int i = 0;//代表行
int j = 0;//代表列
a[0][0] = 1;//先给第一个位置(蛇尾)赋值
while (count != 2)//控制上部分的循环次数
{
if (0 == i || 0 == i && 0 == j)//判断掉头方向(第一个位置处于a[0][0]但是右转)
{
a[i][j+1] = a[i][j] + 1;//赋值(原位置数加一)
j++;//向右刹车
if (n - 1 == i || n - 1 == j)
count++;//统计对角线顶点次数
while (j != 0)//转弯部分
{
a[i+1][j-1] = a[i][j] + 1;//赋值(原位置数加一)
j--;
i++;//向左下移动
}
}
else if (0 == j)//判断掉头方向
{
a[i + 1][j] = a[i][j] + 1;//赋值(原位置数加一)
i++;//向下刹车
if (n - 1 == i || n - 1 == j)
count++;//统计对角线顶点次数
while (i != 0)//转弯部分
{
a[i - 1][j + 1] = a[i][j] + 1;//赋值(原位置数加一)
i--;
j++;//向右上移动
}
}
if (n - 1 == i || n - 1 == j)
count++;//统计对角线顶点次数
while (2 == count&&a[n-1][n-1]==0)//进入下部分并且控制结束
{
if (n - 1 == i)//判断掉头方向
{
a[i][j+1] = a[i][j] + 1;//赋值(原位置数加一)
j++;//向右刹车
while (n - 1 != j)//转弯部分
{
a[i-1][j+1] = a[i][j] + 1;//赋值(原位置数加一)
j++;
i--;//向右上移动
}
}
else if (n - 1 == j)//判断掉头方向
{
a[i+1][j] = a[i][j] + 1;//赋值(原位置数加一)
i++;//向下刹车
while (n - 1 != i)//转弯部分
{
a[i+1][j-1] = a[i][j] + 1;//赋值(原位置数加一)
i++;
j--;//向左下移动
}
}
}
}
for (int i = 0; i < n; i++)//遍历数组
{
for (int j = 0; j < n; j++)
{
if (a[i][j] != 0)//判断输出
printf("%3d ", a[i][j]); //每个数据占三个空格,不足三位数往前填空格
}
printf("\n");//换行
}
return 0;
}
3.2超级圣诞树
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<Windows.h>
int main()
{
int n = 0;
scanf("%d", &n);//接收数据
int a[100][100] = { 0 };
int s = 5;//每个三角形占五列
int k = pow(2, n - 1);//计算(每次复制行数变为原来的两倍)
int r = n + (3 * k);//树干行数加树主体2行数(n是树干占行数,3是每个三角形占行数)
int m = 5;
for (int i = 0; i < n - 1; i++)
{
s = (2 * s) + 1;//计算复制完后的图形的列数从而确定顶点所在列
}
for (int i = r-n; i <r ; i++)
{
a[i][s / 2] = 1;//给树干部分做标记
}
a[0][(s / 2) ] = 1;
a[1][(s / 2)-1] = 1;
a[1][(s / 2) + 1] = 1;
a[2][(s / 2)] = 1;
a[2][(s / 2) -2] = 1;
a[2][(s / 2) + 2] = 1;//先给第一个三角形标记
for (int i = 0; i < n - 1; i++)
{
int p = 0;
int m = 5;
for (int j = 0; j < i; j++)
{
p = m;
m = (2 * p) + 1;//计算扫描区列数
}
int k = pow(2, i);
int r = (3 * k);//计算扫描区的行数
for (int g = 0; g < r; g++)//扫描行
{
for (int q = 0; q < 100; q++)//扫描列
{
if (a[g][q] == 1)//判断是否为标记点
{
a[g +r][q - ((m / 2) + 1)] = 1;//复制左边三角形
a[g +r][q + ((m / 2) + 1)] = 1;//复制右边三角形
}
}
}
}
for (int i = 0; i < 100; i++)//遍历数组打印
{
for (int j = 0; j < 100; j++)
{
if (a[i][j] == 0)//打印空格
printf(" ");
else
{
printf("*");//打印星号
Sleep(1000);//睡眠打印(延迟打印,可以看到过程,更有氛围感!)
}
}
printf("\n");//换行
}
return 0;
}
4.后言
蛇形矩阵和超级圣诞树两道题今天就和大家分享到这啦,这类题还是对我们的观察和思维能力提升挺大的,小伙伴可以多做做。好啦,今天也是年三十,谢谢各位小伙伴垂阅。祝你们龙年大吉,心想事成,提前祝你们新年快乐!