螺旋矩阵算法规律&代码替换(附经典例题)

“ 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!”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ctrl AC

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

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

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

打赏作者

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

抵扣说明:

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

余额充值