题目地址:
ayyzvijos:http://pingce.ayyz.cn/vijos/Problem_Show.asp?id=2017
vijos:https://vijos.org/p/1913
COGS:http://218.28.19.228/cogs/problem/problem.php?pid=1811
题目来源:NOIP2014普及组第三题
问题分析:这道题的内容很易懂,而且容易实现,即直接构造出一个螺旋矩阵,输出对应位置即可。这样的方法大概可以过掉50%的数据。但是,对于100%的数据,n最大可以到30000,如果直接开这么大数组的话,肯定要爆0(内存溢出)。这说明这道题一定有更好的方法。
读题发现,只需输出1个位置的数值即可,而开数组的话,相当于求出了n2个位置,浪费了很多空间。解决办法肯定是不求那些没用的位置,只求一个位置即(i,j)。题中的螺旋矩阵有一个特点,即在每一个正方形边上(如图中线1、2、3),都是螺旋式递增的:
这给了我们一个信息,只要求出(i,j)位置所在的层数,就可以递推得到这个位置的值。观察图形,我们可以得到这个公式:
a[i,j]=该位置所在层的左上角数的值+从左上角到(i,j)顺时针前进的距离-1
例如,在上图中,若求位置为(6,3)位置的值,可以先求出它在第2层,第二层左上角是25,它到点(6,3)的距离为5+1=6,因此a[6,3]=25+6-1=30。思路有了,接下来还有三个问题:
1、如何求层数;
2、如何求这一层左上角位置对应的值;
3、如何求从左上角到这个点前进的距离。
对于问题1,不难发现,点(i,j)所在的层数为:(四个值分别对应(i,j)在上边、左边、下边、右边的情况)
cengshu=min{i,j,n-i+1,n-j+1}
对于问题2,有了层数之后,从最外层往里推,从第1层(最外层)到所在层的上一层的格子数总和+1也就是这层左上角的值了。通过图,我们知道,在7*7的矩阵中,第一层格子数为24=4*(7-1*2+1),第二层格子数为16=4*(7-2*2+1),第三层格子数为8=4*(7-3*2+1),因此,第x层的格子数为 4*(n-2*x+1) (在这里不做严谨证明),然后层层累加即可。
对于问题3,只需分四种情况讨论,详情看代码。
这样,通过数学方法,我们可以快速求出a[i,j],省去了大量时间、空间。
时间复杂度:O(n)
空间复杂度:O(1)
参考代码:
program matrix; var n,i,j,k,l,m,ceng,qishi,bianj1,bianj3:longint; begin assign(input,‘matrix.in‘); reset(input); assign(output,‘matrix.out‘); rewrite(output); readln(n,i,j); k:=i; ceng:=i; if j<ceng then ceng:=j; if (n-i+1)<ceng then ceng:=n-i+1; if (n-j+1)<ceng then ceng:=n-j+1; for k:=1 to ceng-1 do inc(qishi,(n-k*2+1)*4); qishi:=qishi+1; if (n mod 2=1)and(ceng=n div 2+1) then begin writeln(n*n); close(input); close(output); halt; end; bianj1:=ceng; bianj3:=n-ceng+1; if (i=bianj1)and(j<bianj3) then writeln(qishi+(j-bianj1)); if (j=bianj3)and(i<bianj3) then writeln(qishi+(bianj3-bianj1)+(i-bianj1)); if (i=bianj3)and(j>bianj1) then writeln(qishi+(bianj3-bianj1)*2+(bianj3-j)); if (j=bianj1)and(i>bianj1) then writeln(qishi+(bianj3-bianj1)*3+(bianj3-i)); close(input); close(output); end.
matrix.pas