“ Ctrl AC!一起 AC!”
目录
规律
规律来源:螺旋矩阵算法研究
规律总结:
定义顺时针螺旋矩阵从零行零列开始,将螺旋矩阵分层,从第零层开始。如图:
矩阵的边长为N,i表示第i层,x,y表示坐标,t[i]表示第i层左上角的最小值
规律一:矩阵的层数为(N+1)/ 2;
规律二:每层的左上角的值最小,其值为2 * i * (2 * N - 2 * i) + 1
规律三:某点x,y所在的层数NOceng为:min(min(x, y), min(N -x - 1, N - y - 1))
规律四:if (x <= y) 其对应的值为: t[NOceng] + x + y - 2 * NOceng ;
else 其对应的值为: t[NOceng + 1] - x - y + 2 * NOceng ;
规律的代码替换
其中规律一,三无需代码替换,下面进行规律二,四的代码替换:
规律二代码替换:
将矩阵的某层分成如图所示的四部分。那么某层左上角的最小值为前i-1层的数的个数和加一。
前i-1层的数的个数和可通过迭代递归得出。
上代码:
#include<iostream>
using namespace std;
int t[50];//保留每层的左上角最小值
int thestartnum(int N, int i) {//传入第i层,处理第i-1层
if (i == 0) return 0;//第零层返回零
if (i - 1 == 0) return 2 * N + (N - 2) * 2;//第一层返回第零层的数的个数
return (N - (i - 1) * 2) * 2 + (N - i * 2) * 2 + thestartnum(N,i - 1);//处理第i-1层,再传入i-1层,即进一步处理第i-2层
}
int main() {
int N; cin >> N;
int ceng = (N + 1) / 2;
for (int i = 0; i < ceng; i++) {
t[i] = thestartnum(N, i)+1;
}
for (int i = 0; i < ceng; i++) {
cout << t[i] << endl;
}
return 0;
}
规律四代码替换:
定义add为坐标相对于同层左上角最小值的增量,NOceng为坐标所在层数。
如果坐标在同行部分:add=列的差值。
如果坐标在对行部分:add=一行加一列加列的差值
如果坐标在同列部分:add=两行加一列加行的差值
如果坐标在对列部分:add=一行加行的差值
用goto避免同行且对列的重复计算。
其中(N - NOceng * 2 - 1)为一行或一列的增值。
上代码:
int x, y; cin >> x >> y;
int NOceng = min(min(x, y), min(N - x - 1, N - y - 1));
int add;
if (x == NOceng) {
add = y - NOceng; goto label;
}
if (x == (N - NOceng - 1)) {
add = (N - NOceng * 2 - 1) * 2 + (N - NOceng - 1) - y; goto label;
}
if (y == NOceng) {
add = (N - NOceng * 2 - 1) * 3 + (N - NOceng - 1) - x; goto label;
}
add = (N - NOceng * 2 - 1) + x - NOceng;
label:
int ans = t[NOceng] + add;
例题
原题:小兔子捡金币
大意:输入矩阵边长和几个坐标,求坐标对应的值。
(题目的坐标和矩阵是从1行1列开始,而我们研究的是从0行0列开始的)
纯代码AC代码:
#include<iostream>
using namespace std;
int t[5005];//保留每层的左上角最小值
int thestartnum(int N, int i) {//传入第i层,处理第i-1层
if (i == 0) return 0;//第零层返回零
if (i - 1 == 0) return 2 * N + (N - 2) * 2;//第一层返回第零层的数的个数
return (N - (i - 1) * 2) * 2 + (N - i * 2) * 2 + thestartnum(N,i - 1);//处理第i-1层,再传入i-1层,即进一步处理第i-2层
}
int main() {
int N,K; cin >> K>>N;
int ceng = (N + 1) / 2;
for (int i = 0; i < ceng; i++) {
t[i] = thestartnum(N, i)+1;
}
for(int i=0;i<K;i++){
int x, y; cin >> x >> y;
x--, y--;//因为矩阵要从零行零列开始
int NOceng = min(min(x, y), min(N - x - 1, N - y - 1));
int add;//增量
if (x == NOceng) {
add = y - NOceng; goto label;
}
if (x == (N - NOceng - 1)) {
add = (N - NOceng * 2 - 1) * 2 + (N - NOceng - 1) - y; goto label;
}
if (y == NOceng) {
add = (N - NOceng * 2 - 1) * 3 + (N - NOceng - 1) - x; goto label;
}
add = (N - NOceng * 2 - 1) + x - NOceng;
label:
int ans = t[NOceng] + add;
cout << ans << endl;
}
return 0;
}
想通过规律解题,可参考博主的另一篇博客:
POJ 2987:小兔子捡金币(附螺旋矩阵算法研究)
感谢阅读!!!
“ Ctrl AC!一起 AC!”