NOIP2014(普及组)T3 螺旋矩阵

来源:互联网 发布:机器人离线编程 编辑:程序博客网 时间:2024/05/29 09:38

题目描述

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

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

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

1 2 3 4

12 13 14 5

11 16 15 6

10 9 8 7

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

输入描述

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

输出描述

输出共一行,包含一个整数,表示相应矩阵中第i行第j列的数。

样例输入

4 2 3

样例输出

14

数据范围及提示

对于50%的数据,1 ≤ n ≤ 100;

对于100%的数据,1 ≤ n ≤ 30,000,1 ≤ i ≤ n,1 ≤ j ≤ n。


RE解法】模拟矩阵,能拿50分,不多说

#include <iostream>using namespace std;int a[5000][5000];bool flag = false;int n, m, i, j, c, nowx, nowy;int u=-1, d, l=-1, r;int main() {    cin >> n >> i >> j;    i --;    j --;    d=n;    r=n;    while(true) {        while(true) {            c ++;            a[nowy][nowx] = c;            if(nowx == j && nowy == i) {                cout << c << endl;                return 0;            }            if(nowx+1 >= r) break;            if(a[nowy][nowx+1] != 0) break;            nowx ++;        }        c --;        while(true) {            c ++;            a[nowy][nowx] = c;            if(nowx == j && nowy == i) {                cout << c << endl;                return 0;            }            if(nowy+1 >= d) break;            if(a[nowy+1][nowx] != 0) break;            nowy ++;        }        c --;        while(true) {            c ++;            a[nowy][nowx] = c;            if(nowx == j && nowy == i) {                cout << c << endl;                return 0;            }            if(nowx-1 <= l) break;            if(a[nowy][nowx-1] != 0) break;            nowx --;        }        c --;        while(true) {            c ++;            a[nowy][nowx] = c;            if(nowx == j && nowy == i) {                cout << c << endl;                return 0;            }            if(nowy-1 <= u) break;            if(a[nowy-1][nowx] != 0) break;            nowy --;        }        c --;    }    return 0;}


AC解法】分类讨论 总结通项公式

layer:由外到内是第几层

情况1:在第i行就是在第i

  例如在第1行,就是第1

情况2:在第i行,实际是倒数第n-i+1行 在第(n-i+1)

  例如在第n行,实际在第1(n-n+1)

情况3:在第j列就是在第j

  例如在第1列就是第1

情况4:在第j列是从右往左数第n-j+1列 在第(n-j+1)

          例如在第n列是第1

min就是从上下左右四个方向数层数,哪一种最小就是第几层


先根据面积计算左上角的数字;

根据题目要求的点的位置分四种情况:

如果在上边上,直接往右数

如果在右边上,先往右数,再往下数

如果在下边上,先往右,再往下,再往左

如果在左边上,先往右,再往下,再往左,最后往上


【AC_Code】

#include <iostream>using namespace std;inline int Min4(const int a, const int b, const int c, const int d) {return min(a, min(b, min(c, d))); //求四个数的最小值}int Get(int n, int i, int j) {int ans;int layer = Min4(i, j, n-i+1, n-j+1); //层int corner = n * n - (n-2*layer+2)*(n-2*layer+2) + 1; //corner:这一层第一个数(左上角),根据面积求 if(layer == i)        //如果在上边上,直接往右数ans = corner + (j-layer);else if(layer == n-j+1) //如果在右边上,先往右数,再往下数ans = corner + (j-layer) + (i-layer);else if(layer == n-i+1) //如果在下边上,先往右,再往下, 再往左ans = corner + (n-2*layer+1) + (n-2*layer+1) + ((n-layer+1)-j);else if(layer == j)     //如果在左边上,先往右,再往下, 再往左,最后往上ans = corner + (n-2*layer+1) + (n-2*layer+1) + (n-2*layer+1) + ((n-layer+1)-i);/*以上可以合并简化方便计算,为了理解方便就不合并了*/return ans;}int main() {int n, i, j;//cin >> n;cin >> n >> i >> j;//for(int i=1; i<=n; i++, cout << endl)//for(int j=1; j<=n; j++) cout << Get(n, i, j) << ' ';cout << Get(n, i, j) << endl;return 0;}



Thanks#end