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\) 时的螺旋矩阵。
现给出矩阵大小 \(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;
}

浙公网安备 33010602011771号