2023/12/17 n层正方形

这个题历来有很多做法。我的老师,我的学长,我自己感觉有三种做法。(也许?) 

老师的做法如下,他的代码注释很详细,我就不再过多解释了

#include <iostream>
// #include <math.h>
#include <cmath>
#define MAX_NUM (100)
using namespace std;
int main(void)
{
    // 输入层数n
    size_t n = 1;
    cin >> n;

    // 正方形的大小 n+n-1
    size_t NUM = n + n - 1;

    // 建议给学生这样讲,二维动态数组不见得兼容
    int arr[MAX_NUM][MAX_NUM];      

    // 规律 从1开始,每进一层step 数字+1
    for (size_t step = 0; step < n; step++)
    {
        // 每进一层,边框横坐标 -1
        for (size_t i = step; i < NUM-step; i++)
        {
             每进一层,边框纵坐标 -1
            for (size_t j = step; j < NUM-step; j++)
            {
                // 找到缩小后矩阵的边框 上框、左框
                if ((i == step) || (j == step) )                
                {
                    arr[i][j] = step + 1;
                }

                // 找到缩小后矩阵的边框 下框、右框
                if((i == (NUM-step-1)) || (j == (NUM - step-1))){
                    arr[i][j] = step + 1;
                }
            }
        }
    }

    // 输出矩阵
    for (size_t i = 0; i < NUM; i++)
    {
        for (size_t j = 0; j < NUM; j++)
        {

            cout << arr[i][j]<< ' ';
        }
        cout << endl;
    }
}

第二种是学长的做法。他是从这个图形的对称性入手解决问题。这里贴出他的文章链接:

观察结构,发现所要输出的方阵根据主对角线(左上到右下)对称,因此只需找到输出主对角线以上(含主对角线)的部分即可。

首先解决主对角线(第一组数),主对角线数字顺序为1,2,……,n-1,n ,  n-1,……,2,1也是对称的,且根据 n 对称。为了方便起见,令for语句中 i 的初始值为1,则此时每个 i 对应的都是arr[i-1][i-1]。为了方便描述,不妨将数组中的元素命名为m,当 i <=n时,m=i;当i > n时,m=2* n-i。

此时主对角线  (第一行第一列,第二行第二列,……,第2* n-1行第2* n-1列)   解决完毕,下面来看第二组  (第一行第二列,第二行第三节,……,第2* n-2行第2* n-1列)  。

此时第二组数的总数为2* n-2,此时最中间的数为n-1(此时最中间的数有两个,但无妨),此时每个 i 对应的数组元素是arr[i-1][i-1+]〕(即arr[i-1][ i ]),同样用m代替。和第一组类似,当 i<=n时,m=i;当 i > n时,由于第二组总数个数为偶数,因此第一组公式不合适,因此需要找一个同时适用于奇数个数和偶数个数的公式。此时考虑第三组数(第一行第三列,第二行第四列,……,第n-3行第n-1列) 最中间的数字也是n-1,进一步证明了上面那个公式不合适。接下来有两种方法解决这个问题 :

方法一   
只讨论奇数组(1、3、5、……、2* n-1组) 

这时第一组数中那个公式就可以用了,即第 j 组数的个数为2* n-j,最中间的数为(2* n-j+1)/2  (不妨记为n1),当 i<=n1时,m=i;当i   >n1时,m=2*n1-i 将所有奇数组放到一个for循环中

这时可以发现,所有空缺的偶数组的数都是前面的数和后面的数的平均数

方法二   
从出现的问题出发,找到一个新的公式

为了方便起见,不妨拿n=3举例,此时第一组数为1,2,3,2,1;第二组数为1,2,2,1;如果按照上面那个公式第一组数在 i >3时,依次为2*3-4,2*3-5  第二组数在 i >2时,依次为2*2-3,2*2-4 显然第二组数与我们想要得到的不同,结果差了1,因此考虑如何才能得到我们想要的结果,也许(2*2+1)-3,(2*2+1)-4可以得到,这里可以用if条件语录,但是有些繁琐,我们需要得到一个适用于所有情况的公式,第 j 组中间的数为n-j(记作a),第 j 组数的个数为2* n-1-j(记作b),由2* a-1=b可得,a=( b+1)/2  (此时不论b为奇数还是偶数,由int整型得到的a为一个整数),于是 i > n1时公式可以改为m=2* a-i,此时将所有数放到for循环中。

以上两个方法自行选择

得到主对角线及主对角线以上部分的数后,主对角线下的数就很容易得到了,由矩阵对称可令a[i-1-j][i-1]=a[i-1][i-1-j]    于是,所要求得的矩阵就完全求出了

运算部分需要有嵌套循环,内层为 i 的循环,i 表示第几行,外层为m的循环,i + m表示第几列
————————————————
版权声明:本文为CSDN博主「玄殛~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_73552988/article/details/127855127

http://t.csdnimg.cn/TqZS1icon-default.png?t=N7T8http://t.csdnimg.cn/TqZS1第三种是我自己的想法。我拿到这个问题先观察了它给出的样例,发现了一个小窍门(应该算是?)

我们来观察这个图案。每个位置所对应的数字其实是该位置到四条边的距离取最小值。如果说1到四条边的距离为1,那么我们可以如下图推出每一个位置所对应的数字。比如下图。

这样就可以通过代码解决问题了。 

#include<iostream>
using namespace std;

int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < 2 * n - 1; i++)
	{
		for (int j = 0; j < 2 * n - 1; j++)
		{
			int num = min(min(i, j), min(2 * n - i - 2, 2 * n - j - 2))+1;
			cout << num << " ";
		}
		cout << endl;
	}

	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值