数学一本通6.2 数字方阵

定义

其实数字方阵并不是一种数学工具(?

可以当做不用运算的、行数=列数的 矩阵。

从语文的角度看:

    矩形->矩阵 长方形的

(正)方形->方阵 正方形的

???

性质

主要总结几种基本的变换

1.垂直对称 f'(i,j)=f(i,n+1-j)

2.水平对称 f'(i,j)=f(n+1-i,j)

3.对角线(左上-右下)对称 f'(i,j)=f(j,i)

4.对角线(左下-右上)对称 f'(i,j)=f(n+1-j,n+1-i) //原文貌似有误

5.中心对称(水平对称+垂直对称) f'(i,j)=f(n+1-i,n+1-j)

6.顺时针90度(水平对称+对角线对称) f'(i,j)=f(n+1-j,i)

7.顺时针90度(垂直对称+对角线对称) f'(i,j)=f(j,n+1-i)

都易证

为什么我觉得会出锅

例题

主要部分。这算是全书最水的部分了……全是模(%)拟

方法:模拟法、归纳法。

例6.2-1 (NOIp2015 提高组)n阶奇数幻方/神奇(jī)的幻方

(https://www.luogu.org/problemnew/show/P2615)

n为奇数时,输出n阶幻方。

分析题目中的四个变换方式:

1.若(K-1)在第一行但不在最后一列,则将K填在最后一行,(K-1)所在列的右一列

 

2.若(K-1)在最后一列但不在第一行,则将K填在第一列,(K-1)所在行的上一行

3.若(K-1)在第一行最后一列,则将K填在(K-1)的正下方;

 

4.若(K-1)既不在第一行,也最后一列,如果(K-1)的右上方还未填数,则将K填在 (K-1)(K1) 的右上方,否则将 LL 填在 (K-1)(K1) 的正下方。

 ???规律很明显???

综上所述,可得:

①当当前位置的右上一格为空时 填进去

②当……不为空时 填在下面(在k<n^2范围内肯定为空,别问我我也不会证)

    (但是其实有一种玄学反证:如果不为空,题目出错,所以为空)

    (这个说法我自己都不信,但是考试时还是很好用的 。。。)

代码:

#include<iostream>
#include<iomanip>
using namespace std;
int n,x,y,a[55][55];
int main() {
    ios::sync_with_stdio(false);
    cin>>n;
    y=n/2;
    for(int i=1;i<=n*n;i++) {
        a[x][y]=i;
        x--,y++;
        x+=n,y+=n;
        x%=n,y%=n;
        if(a[x][y]) x+=2,y--;
        x+=n,y+=n;
        x%=n,y%=n;
    }
    for(int i=0;i<n;i++) {
        for(int j=0;j<n;j++)
            cout<<a[i][j]<<' '; 
        cout<<endl;
    }
    return 0;
}

 

例6.2-2 N阶斜线方阵

给出n,输出如图所示的一个n^2方阵

  1   2   4   7 11

  3   5   8 12 16

  6   9 13 17 20

10 14 18 21 23

15 19 22 24 25

首先可以按照斜线填数。

然后注意到,相同斜线上的数横纵坐标之和相等。

代码:

#include<iostream>
#include<iomanip>
using namespace std;
int n,count=1,a[25][25];
int main() {
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=i;j++) {
            a[j][i+1-j]=count++;
        }
    }
    for(int i=n-1;i>=1;i--) {
        for(int j=1;j<=i;j++) {
            a[n-i+j][n-j+1]=count++;
        }
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++)
            cout<<setw(3)<<a[i][j]<<' '; 
        cout<<endl;
    }
    return 0;
}

例6.2-2 (NOIp2014 普及组)N阶螺旋方阵/螺旋矩阵

(我记得17年刚学OI的时候有一次比赛,这题是第二题。然后我调了一个小时发现数据太大没法模拟……)

用实验法 可以得出此题应该用归纳法,即数学推理法。模拟是不行的。

由于这是正方形,可以像靶形数独像箭靶一样,将方格分层,再处理一层的环形。

首先设左上角数字为k。

  • 第一行:显而易见可得f(i,1)=i+k-1;
  • 最后一行:右下角为k+2n-2,f(i,n)=(k+2n-2)+(n-i)=k+3n-i-2
  • 第一列:左下角为k+3n-3,f(1,i)=(k+3n-3)+(n-i)=k+4n-i-3
  • 最后一列:右上角为k+n,f(n,i)=k+n+i-2

注意到每一层都是 加一个k,k可以在前一层的基础上求出。

有一个细节:若之前求k少加了1,之后要少减去1。

代码:

#include<iostream>
#include<iomanip>
using namespace std;
int n,i,j;
int solve(int n,int x,int y){
    if(y==1) return x;
    if(y==n) return 3*n-x-1;
    if(x==1) return 4*n-y-2;
    if(x==n) return n+y-1;
    return solve(n-2,x-1,y-1)+4*(n-1);
}
int main() {
    ios::sync_with_stdio(false);
    cin>>n>>i>>j;
    cout<<solve(n,j,i);
    return 0;
}

总结

当数据比较小时用模拟法。模拟法要抓住“有规律的变化”,用循环求解。

当数据比较大,或规律明显时用归纳法。归纳法参考等差数列,要利用“初值”,“公差”,“项数”分析公式,也要在最后用加上常数的方法进行调整。另外还要注意数值变化的方向。

你们都听懂了吗?赶紧动手试试吧!(唐突)

猜你喜欢

转载自www.cnblogs.com/ehznehc/p/10331323.html