NOIP
【螺旋矩阵】
题目描述
本质上这题是一道纯粹的数学题,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) //如果位于当前矩阵的上边框,则直接返回jreturn j;else if(j==n)//如果位于当前矩阵的右边框,则数字是n+i-1return n+i-1;else if(i==n)//如果位于当前矩阵的下边框,则数字是1+3(n-1)-(j-1)=3n-j-1return 3*n-j-1;else if(j==1)//如果位于当前举证的左边框,则数字是1+3(n-1)+n-2-(i-2)=4n-i-2return 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;
}
NOIP
【螺旋矩阵】
题目描述
本质上这题是一道纯粹的数学题,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) //如果位于当前矩阵的上边框,则直接返回jreturn j;else if(j==n)//如果位于当前矩阵的右边框,则数字是n+i-1return n+i-1;else if(i==n)//如果位于当前矩阵的下边框,则数字是1+3(n-1)-(j-1)=3n-j-1return 3*n-j-1;else if(j==1)//如果位于当前举证的左边框,则数字是1+3(n-1)+n-2-(i-2)=4n-i-2return 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;
}