1.问题描述:印刷电路板将布线区域划分成m*n个方格阵列,如图(1)所示。精确的电路布线问题要求确定连接方格a的中点到方格b的中点的最短布线方案。
在布线时,电路只能沿直线或直角布线,如图(2)所示。为了避免线路相交,已布了线的方格做了封锁标记,其他线路不允许穿过被封锁的方格。
图1 图2
在本问题当中,其他条件不变,但要求在布线时,电路只能沿斜线布线(田字布线),如下图所示:
2.求解思路:虽要求有所改变,但解题思路仍然相似,同样可以使用队列式分支界限法来解决问题。从起始位置a开始,将a作为第一个扩展节点,并且将a周围斜线可达方格看作可行节点并放入队列当中,同时这些节点记作1,再从队列中取出首个节点,将该节点周围可达方格当作可行节点放入队列,同时将其记作2,不断循环此步骤,直到队列为空。
3.算法具体代码如下:
# 田字布线问题
length = 6
m = length
n = length
grid = [[0 for _ in range(length + 2)] for _ in range(length + 2)]
def print_grid():
for i in range(1, length + 1):
for j in range(1, length + 1):
print(f'{grid[i][j]:>3}', end='')
print()
print()
def find_path(start, finish): # 寻找路径
# 找到每个相邻节点的斜边节点,并且遍历
next_step = [(1, 1), (-1, 1), (1, -1), (-1, -1)]
here = start
grid[start[0]][start[1]] = 1
q = []
while True:
for dx, dy in next_step:
next_pos = (here[0] + dx, here[1] + dy)
if 1 <= next_pos[0] <= length + 1 and 1 <= next_pos[1] <= length + 1 and grid[next_pos[0]][next_pos[1]] == 0:
grid[next_pos[0]][next_pos[1]] = grid[here[0]][here[1]] + 1
if next_pos == finish:
break
q.append(next_pos)
if next_pos == finish:
break
if not q:
return False
here = q.pop(0)
path_len = grid[finish[0]][finish[1]]
path = []
here = finish
for j in range(path_len - 1, -1, -1):
path.append(here)
for dx, dy in next_step:
next_pos = (here[0] + dx, here[1] + dy)
if 1 <= next_pos[0] <= length + 1 and 1 <= next_pos[1] <= length + 1 and grid[next_pos[0]][next_pos[1]] == j:
break
here = next_pos
return path_len, path
# 将已经布线的方格设置为 -1
grid[2][3] = grid[3][4] = grid[3][5] = grid[4][2] = -1
start = (1, 1) # 布线起始点
print(f'#起始点: {start[0]:>3}{start[1]:>3}')
finish = (4, 4) # 布线终点
print(f'#终点: {finish[0]:>3}{finish[1]:>3}')
path_len_and_path = find_path(start, finish)
if path_len_and_path is False:
print("No path found.")
else:
path_len, path = path_len_and_path
print('\n#最终结果: ')
print_grid()
print(f'#最短路径长度: {path_len - 1}')
for i, pos in enumerate(path):
if i > 0:
print(f'->({pos[0]},{pos[1]})', end='')
print()
将起始点设置为(1,1),终点设置为(4,4)时,运行结果如下: