zoukankan      html  css  js  c++  java
  • 数学一本通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$4度(垂直对称+对角线对称) $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)的右上方,否则将K填在(K-1)的正下方。

     ???规律很明显???

    综上所述,可得:

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

    ②当……不为空时 填在下面(在$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;
    }

    总结

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

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

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

  • 相关阅读:
    建模算法(十)——灰色理论之关联度分析
    建模算法(八)——插值
    建模算法(七)——排队论模型
    建模算法(六)——神经网络模型
    建模算法(五)——图与网络
    [gpio]Linux GPIO简单使用方式2-sysfs
    [Kernel]理解System call系统调用
    [gpio]Linux GPIO简单使用方式1-sysfs
    [misc]如何在嵌入式平台使用printf功能
    [wifi]wifi模块操作
  • 原文地址:https://www.cnblogs.com/ehznehc/p/10331323.html
Copyright © 2011-2022 走看看