【NOIP2014 普及组】螺旋矩阵

【NOIP2014 普及组】螺旋矩阵

一、题目

【NOIP2014 普及组】螺旋矩阵

时间限制: 1 Sec  内存限制: 128 MB
提交: 18  解决: 0
[提交][状态][讨论版]

题目描述

一个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。 

 

二、分析及代码

【题解】

首先,本题有两种思路。

1.老老实实填数组。(此方法简单易懂,但当矩阵过大时,就会出现数组开不够大,或long long也不够的情况)

2. 用算法找规律,但规律不是一般的难找。我就简单说说我找到的规律。

 

 

 

1

2

3

4

12

13

14

5

11

16

15

6

10

9

8

7

 

1

2

4

3

 

首先对比两表,你就会发现下表就是上表中间四格每个减去12,正好就是外圈12个数中最大的;

而12就是外圈边长的4倍减4;

于是,就成了这样

1

2

3

4

12

1

2

5

11

3

4

6

10

9

8

7

红色是内圈,黑色是外圈

红色基数为12,黑色基数为0

 

同时,每一圈最上方的一行就是i+j-1的值。

最右方的一列就是i+j-1的值。

最下方的一行就是4n-i-j-1的值。

最左方的一列就是4n-i-j-1的值。

(一定要记得加上外圈基数哦!)

DP思路

状态:

用f[n][i][j]表示n阶方块i,j位置的值。

对于外圈的:

i表示列,j表示行

if(i>=j)

f[n][i][j]= i+j-1

if(i<j)

f[n][i][j]= 4n-i-j-1

对于内圈:

f[n][i][j]= f[n-2][i-1][j-1]+n*n-(n-2)*(n-2);

初始状态:

f[1][1][1]=1

f[2][1][1]=1

f[2][2][1]=2

f[2][2][2]=3

f[2][1][2]=4

外圈表示:

if(j==1||i==1||j==n||i==n)

内圈表示:

i>1&&i<n&&j>1&&j<n

代码

 1 #include <iostream>
 2 using namespace std;
 3 int i=2,j=3,n=3;
 4 void luo(int n1)
 5 {
 6     int a=0,k,l;
 7     for (l=1;l<n1;l++)
 8     {
 9     a=a+n*4-l*8+4;
10     }
11     if (i>=j) printf ("%d",a+i+j-2*n1+1);
12         else printf ("%d",a+(n-2*n1+1)*4-i-j+n1+n1+1);
13 }
14 int main()
15 {
16     freopen("in2.txt","r",stdin);
17     int i1,j1;
18     scanf ("%d %d %d",&n,&j,&i);
19     //cout<<n<<j<<i;
20     i1=i;
21     j1=j;
22     if (i1>n/2) i1=n-i1+1;
23     if (j1>n/2) j1=n-j1+1;
24     if(i1>j1) luo(j1);
25         else luo(i1);
26 }

 

原文地址:https://www.cnblogs.com/Renyi-Fan/p/7385514.html