PTA 7-8 螺旋方阵 & 洛谷P2239 [NOIP2014 普及组] 螺旋矩阵 题解

PTA 7-8 螺旋方阵 & 洛谷P2239 [NOIP2014 普及组] 螺旋矩阵 题解

题目:

所谓“螺旋方阵”,是指对任意给定的N,将1到N×N的数字从左上角第1个格子开始,按顺时针螺旋方向顺序填入N×N的方阵里。本题要求构造这样的螺旋方阵。

输入格式:
输入在一行中给出一个正整数N(<10)。

输出格式:
输出N×N的螺旋方阵。每行N个数字,每个数字占3位。

输入样例:
5
输出样例:
  1  2  3  4  5
 16 17 18 19  6
 15 24 25 20  7
 14 23 22 21  8
 13 12 11 10  9

原题

这个题目实际是弱化中的弱化版,原题是 [NOIP2014 普及组] 螺旋矩阵:

题目描述

一个 \(n\) 行 $ n$ 列的螺旋矩阵可由如下方法生成:

从矩阵的左上角(第 \(1\) 行第 \(1\) 列)出发,初始时向右移动;如果前方是未曾经过的格子,则继续前进,否则右转;重复上述操作直至经过矩阵中所有格子。根据经过顺序,在格子中依次填入 \(1, 2, 3, \dots, n^2\),便构成了一个螺旋矩阵。

下图是一个 \(n = 4\) 时的螺旋矩阵。

\[\begin{pmatrix} 1 & 2 & 3 & 4 \\ 12 & 13 & 14 & 5 \\ 11 & 16 & 15 & 6 \\ 10 & 9 & 8 & 7 \\ \end{pmatrix}\]

现给出矩阵大小 \(n\) 以及 \(i\)\(j\),请你求出该矩阵中第 \(i\) 行第 \(j\) 列的数是多少。

输入格式

共一行,包含三个整数 \(n\), \(i\), \(j\),每两个整数之间用一个空格隔开,分别表示矩阵大小、待求的数所在的行号和列号。

输出格式

一个整数,表示相应矩阵中第 \(i\) 行第 \(j\) 列的数。

样例 #1

样例输入 #1

4 2 3

样例输出 #1

14

【数据说明】

对于 \(50\%\) 的数据,\(1 \leqslant n \leqslant 100\);

对于 \(100\%\) 的数据,\(1 \leqslant n \leqslant 30,000,1 \leqslant i \leqslant n,1 \leqslant j \leqslant n\)

先写原题:

观察数据,如果一个个位置模拟必定超时暴毙,我们需要采取数学方法推导优化。
观察规律,我们不难发现每一个位置的数字都有一定数学规律,但实际我比较菜,算不出来,所以自己想了另一种比较直观的模拟方法:

因为这个矩阵的生成方式是由外到内一圈一圈生成的,我们可以很容易的知道一圈有多少数而不用一个一个位置的推导,于是对于给定位置,我们先剥除矩阵生成到此位置时会完整生成的外圈,由于矩阵是 \(\texttt{n*n}\) 的完全矩阵,其中任意一个位置都在一个对称的圈上,稍微一想便可以知道,我们剥除了生成给定位置的矩阵所经过的完整外圈后,给定位置一定在剩下的尚未生成的新矩阵的最外圈,(反证法:若不在最外圈,则外圈一定已经被剥除了),此时我们分类讨论它在上下左右哪一条边,再加上对应的偏移量即可得到给定位置上的数字,复杂度相比模拟大幅降低,码力要求也大幅下降,可以轻松飞过。

//cpp
#include<bits/stdc++.h>
using namespace std;
int n, x, y;

int main(){
    cin >> n >> x >> y;
    int row = min(x-1, n-x), column = min(y-1, n-y);
    int tmp = min(row, column);
    long long sum = 0;

    x -= tmp; y -= tmp;
    //printf("tmp: %d\n", tmp);

    for(int i=1; i<=tmp; i++){
            sum += 4*(n-i*2+1);
    }

    if(x == 1) cout<< sum + y;
    else if(x == n-tmp*2) cout<< sum + (n-tmp*2-1)*2 + n-tmp*2-y+1;
    else if(y == 1) cout<< sum + (n-tmp*2-1)*3 + n-tmp*2-x+1;
    else cout<< sum + n-tmp*2-1 + x ;
    return 0;
}

PTA 7-8

非常显然,原题只要求我们输出给定位置的一个数,而改编题我们可以看做要求输出每一个位置的数,我们遍历整个矩阵,按顺序输出给定位置的各个数即可。

满分代码:

//cpp
#include<bits/stdc++.h>
using namespace std;
int n;
int mapp[12][12];

int work(int x, int y){
    int row = min(x-1, n-x), column = min(y-1, n-y);
    int tmp = min(row, column);
    int sum = 0;
    int ans = 0;
    x -= tmp; y -= tmp;
    //printf("tmp: %d\n", tmp);

    for(int i=1; i<=tmp; i++){
            sum += 4*(n-i*2+1);
    }

    if(x == 1) ans= sum + y;
    else if(x == n-tmp*2) ans= sum + (n-tmp*2-1)*2 + n-tmp*2-y+1;
    else if(y == 1) ans= sum + (n-tmp*2-1)*3 + n-tmp*2-x+1;
    else ans= sum + n-tmp*2-1 + x ;
    return ans;
}
int main(){
    cin >> n;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            mapp[i][j] = work(i, j);

    for(int i=1; i<=n; i++, cout<<endl)
        for(int j=1; j<=n; j++)
            printf("%3d", mapp[i][j]);
    
    return 0;
}
posted @ 2024-10-24 12:52  [丘李]Chilllee  阅读(218)  评论(0)    收藏  举报