H. 蛇形矩阵 Plus 题解【递推找规律】

1 篇文章 0 订阅

题意:

输入一个常数n,求出n阶螺旋方阵的每一行的和。

思路:

首先我想到的是直接写一个求螺旋矩阵的程序,把每一行的和直接求出来,但是后来我发现这个题数据很大,这个方法只能过几个用例,所以肯定有特殊的方法求解。于是我们想到了找规律递推一下。

举个例子,先观察n = 9的时候。

对应的蛇形矩阵如下

1 2 3 4 5 6 7 8 9

32 33 34 35 36 37 38 39 10

31 56 57 58 59 60 61 40 11

30 55 72 73 74 75 62 41 12

29 54 71 80 81 76 63 42 13

28 53 70 79 78 77 64 43 14

27 52 69 68 67 66 65 44 15

26 51 50 49 48 47 46 45 16

25 24 23 22 21 20 19 18 17

第一行的和是S1 = 9*10/2=45。(从1加到n,等差数列求和公式)

第二行前8位比 第一行多31,第9位多1,S2 = 31*8+1+S1=294

第三行第2位到第7位比第二行多23, 第1位少1,后1位多1正好抵消,第8位多1,所以S3 = 23*6+1+S2=433

第四行第3位到第6位比第三行多15, 前2位少1,后2位多1正好抵消,第7位多1,所以S4 = 15*4+1+S3=494

第五行第4位到第5位比第三行多7, 前3位少1,后3位多1正好抵消,第6位多1,所以S5 = 7*2+1+S4=509

这是上面的前半部分的规律:假设两个变量a,b 从a = 4 * n - 5 (4*9-5=31), b = n - 1 (9-1=8)开始,a依次减8,b依次减2

S(n)=S(n-1)+1+a*b

第六行比第五行前4位少1, 后4位多1,中间1位少3,S6 = S5-1*3=506

第七行比第六行前3位少1, 后3位多1,中间3位少11, S7 = S6 - 3*11=473

第八行比第七行前2位少1, 后2位多1,中间5位少19, S8 = S7 - 5*19=378

第九行比第八行前1位少1, 后1位多1,中间7位少27, S9 = S8 - 7*27=189

后半部分的规律是从a = 3, b = 1开始,a依次加8, b依次加2 即 S(n)=S(n-1)-a*b

以上是n为奇数的规律,偶数的规律也类似:以n = 6为例:

对应的蛇形矩阵如下

1 2 3 4 5 6

20 21 22 23 24 7

19 32 33 34 25 8

18 31 36 35 26 9

17 30 29 28 27 10

16 15 14 13 12 11

前三行的规律和上面一样,

S1 = 6 * 7 / 2 = 21

S2 = 19 * 5 + 1 + S1=117

S3 = 11 * 3 + 1 + S2=151

即 S(n)=S(n-1)+1+a*b

后三行的规律是

S4 = S3 + 4

S5 = S4 - 2 * 7

S6 = S5 - 4 * 15

多找几组偶数会发现每次都是这样的规律,后半部分的第一行 = <u>前半部分的最后一行 + 4</u>,即 S(n)=S(n-1)+4

然后后面几行的规律都是依次它的上一行减去a*b, a最开始为2,b最开始为7, 之后依次a+=2,b+=8. 即S(n)=S(n-1)-a*b.

所以矩阵分为奇数阶和偶数阶两种情况,并且每种情况还要分为上下两半部分进行计算,差别也是比较小的,注意此题中变量最好全部用 long long ,因为测试数据有一些数据过大会超过 int 。

具体解释看下面代码:

#include<iostream>
using namespace std;
typedef long long ll;//注意用LONG LONG
ll n;
int main()
{
    while(cin >> n)
    {
        if(n%2==1)//n为奇数时
        {
            ll a1 = (n + 1) * n / 2;//等差数列求和公式求出第一行的值
            cout<<a1<<endl;
            ll a = 4 * n - 5, b = n - 1;//a,b初始值
            for(int i = 2; i <= (n + 1) / 2; i++)//前半部分输出
            {
                a1 = a1 + 1 + a * b;
                a -= 8;
                b -= 2;
                cout<<a1<<endl;
            }
            a = 3, b = 1;
            for(int i=(n+1)/2+1 ; i <= n; i++) //后半部分输出
            {
                a1 = a1 - a * b;
                cout<<a1<<endl;
                a += 8;
                b += 2;
            }
        }
        else//n为偶数时
        {
            ll a1 = (n + 1) * n / 2;//输出第一行的值
            cout<<a1<<endl;
            ll a = 4 * n - 5, b = n - 1;//对a和b赋初值
            for(int i = 2; i <= (n + 1) / 2; i++)//前半部分和之前一样的规律
            {
                a1 = a1 + 1 + a * b;
                a -= 8;
                b -= 2;
                cout<<a1<<endl;
            }
            a1 += 4;
            cout<<a1<<endl;//中间的特殊一行直接加 4 规律
            a = 2, b = 7;
            for(int i=(n+1)/2+2; i <= n; i++) //继续后半部分输出
            {
                a1 = a1 - a * b;
                a += 2;
                b += 8;
                cout<<a1<<endl;
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值