题意:
输入一个常数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;
}