python3 题解(15)螺旋填充方阵

本文介绍如何使用Python3将1到n²的自然数按顺时针方向螺旋填充n阶方阵。通过建立二维数组,记录当前位置、填充数字及填充方向,遇到边界或已填充位置时改变方向。利用映射处理方向转换,也可用复数乘法规则或直接定义四个基本方向来实现。

螺旋填充方阵

【问题】用1…n2n^2n2的自然数顺时针方向螺旋填充一个n阶方阵。
当 n = 7 的时候,如下:
在这里插入图片描述
先做一个空的二维数组代表方阵。
始终记录当前的位置,当前填充的数字,当前的填充方向。
当遇到阻力(出界或者撞上了已填的数字)以后,改变填充的方向。

from collections import namedtuple

Posi = namedtuple('Posi', 'row col')  # 位置包含行号和列号
Dire = namedtuple('Dire', 'dr dc')    # 移动方向包含行的变化、列的变化

def next_dire(x):
	return {
		Dire(0,1): Dire(1,0),
		Dire(1,0): Dire(0,-1),
		Dire(0,-1): Dire(-1,0),
		Dire(-1,0): Dire(0,1)
	}[x]

def next_posi(p, d):
	return Posi(p.row + d.dr, p.col + d.dc)

def fang(n):
	da = [[0 for j in range(n)] for i in range(n)]
	p = Posi(0,0)
	d = Dire(0,1)
	c = 1
	while c <= n*n:
		da[p.row][p.col] = c
		c += 1
		p2 = next_posi(p,d)
		if p2.row < 0 or p2.row == n or p2.col < 0 or p2.col == n \
		or da[p2.row][p2.col] != 0:
			d = next_dire(d)
			p2 = next_posi(p,d)
		p = p2
	return da

def disp(x):
	for row in x:
		for i in row:
			print("{:3d}".format(i), end = ' ')
		print()

if __name__ == '__main__':
	disp(fang(7))

为了更清楚地表示位置方向这些概念,使用了命名元组。
在计算当前方向转向后的下一个方向时,用了映射。

这里的方向计算还可以用复数乘法的性质,以数学公式表达向右转的概念。

如果不喜欢抽象。也可以老老实实地:
向右走,然后向下走,然后向左走,然后向上走,然后向右走…

这样代码会长一些:

def fang(n):
	da = [[0 for j in range(n)] for i in range(n)]
	p = (0,0)
	c = 1

	def go_right(p, c):
		da[p[0]][p[1]] = c
		p2 = (p[0],p[1]+1)
		if p2[1] == n or da[p2[0]][p2[1]] != 0: raise Exception("No way")
		return p2, c+1

	def go_down(p,c):
		da[p[0]][p[1]] = c
		p2 = (p[0]+1,p[1])
		if p2[0] == n or da[p2[0]][p2[1]] != 0: raise Exception("No way")
		return p2, c+1

	def go_left(p,c):
		da[p[0]][p[1]] = c
		p2 = (p[0],p[1]-1)
		if p2[1] < 0 or da[p2[0]][p2[1]] != 0: raise Exception("No way")
		return p2, c+1

	def go_up(p,c):
		da[p[0]][p[1]] = c
		p2 = (p[0]-1,p[1])
		if p2[0] < 0 or da[p2[0]][p2[1]] != 0: raise Exception("No way")
		return p2, c+1

	def loop_do(f, p, c):
		try:
			while True: 
				p, c = f(p, c)
		except:
			return p, c

	while True:
		p, c = loop_do(go_right, p, c)
		if c >= n*n: break;
		p, c = loop_do(go_down, p, c)
		if c >= n*n: break;
		p, c = loop_do(go_left, p, c)
		if c >= n*n: break
		p, c = loop_do(go_up, p, c)
		if c >= n*n: break;

	return da

def disp(x):
	for row in x:
		for i in row:
			print("{:3d}".format(i), end = ' ')
		print()

if __name__ == '__main__':
	disp(fang(7))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值