NOIP-2014-J2-T3

【螺旋矩阵】
题目描述

本质上这题是一道纯粹的数学题,n阶矩阵,按蛇形螺旋矩阵方向顺时针填好1~n^2的所有数字后,然后求矩阵任意一个第i行第j列的位置的数字。

通过找规律,可以直接找出计算公式,在O(1)的时间内给出结果。
将矩阵由外到内,看做是一层一层包裹起来的形状,类似洋葱头一样。

首先观察每一层的边长的变化规律,以及每一层左上角起点位置的数字规律
在这里插入图片描述
然后对于给定的坐标(i, j),首先判断出这个点在某第k层,
k=min(i, j, n-j+1, n-i+1)

然后计算其与所在层的左上角起点坐标(k,k)的距离,然后结合起点坐标(k,k)的数字,即可推算出其对于的数字了。

分两种情况讨论一下。
1、当该点在某第k层的上半角时。
在这里插入图片描述

如上图所示,此刻(i, j)满足的条件是i==k,或者j=n-k+1,这种情况下,(i,j)位置的数字就等于起点坐标(k,k)的数字f(k)加上(i,j)到(k,k)的距离,i-k+j-k,即从起点开始顺时针走了(i-k+j-k)步。

在这里插入图片描述

如果(i,j)在矩阵的下半角,此刻(i,j)满足的条件是j==k,或者i=n-k+1,此刻将起点转换一下,视右下角的点为起点,该点的坐标是(n-k+1, n-k+1),其数字是f(k)+2*(当前层的边长-1),即f(k)+2*(n-2*(k-1)-1),这样的话(i,j)坐标的数字是:
新的起点的数字:f(k)+2*(n-2*(k-1)-1),加上沿这个新起点顺时针向左向上游走到(i,j)走过的步数,abs(i-(n-k+1)) + abs(j-(n-k+1))。

#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int n, i, j, start;
	cin >> n >> i >> j;
	int k = min(min(min(i, j), (n-i+1)), (n-j+1));//定位在第k层
	start = 4 * (k - 1) * (n - k + 1) + 1;//第k层的起点对应的数字
	if(i==n-k+1||j==k){//如果在下半部分
	    //将右下角当做起点,其数字是左上角的数字加上2*(当前层的边长-1)
	    start += 2 * (n - 2 * (k - 1) - 1);
	    //将右下角当做起点,其坐标是(n-k+1, n-k+1)
	    k = n-k+1;
	}
	cout << start + abs(i - k) + abs(j - k);
	return 0;
}

除了这样直接算出,也可以通过循环的方式来计算得出,同样一层一层地往里找这个点,时间复杂度o(n)

#include<iostream>

using namespace std;
//dfs(n, i, j)表示当前n阶的螺旋举矩阵当中坐标(i, j)处的数字
int dfs(int n, int i, int j){
    if(i==1) //如果位于当前矩阵的上边框,则直接返回j
        return j;
    else if(j==n)//如果位于当前矩阵的右边框,则数字是n+i-1
        return n+i-1;
    else if(i==n)//如果位于当前矩阵的下边框,则数字是1+3(n-1)-(j-1)=3n-j-1
        return 3*n-j-1;
    else if(j==1)//如果位于当前举证的左边框,则数字是1+3(n-1)+n-2-(i-2)=4n-i-2
        return 4*n-i-2;
    else //否则继续往里面的层找,将问题递归转换为求n-2阶矩阵中坐标(i-1, j-1)处的数字,再加上外圈周长4*(n-1)即可
        return dfs(n-2, i-1, j-1) + 4*(n-1);
}
int main()
{
	int n, i, j, start;
	cin >> n >> i >> j;
    cout << dfs(n, i, j) << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

严老师编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值