房间和传送门问题
需求分析:
在 n 个房间之间,有 若干传送门连接,编程求解从房间 a 出发至房间 b 的最小通过传送门数。
示例:
房间数 num = 5
各房间之间的传送门编号:
rms = [{1,5},{2,3,8},{1,3,6},{4,2,6,9},{5,7}]
从房间 a 至房间 b 的计算结果:
a = 2
b = 5
各房间传送门编号:[{1, 5}, {8, 2, 3}, {1, 3, 6}, {9, 2, 4, 6}, {5, 7}]
从某个房间到其它房间的链表:{1: [3, 5], 2: [3, 4], 3: [1, 2, 4], 4: [2, 3], 5: [1]}
房间2至房间5的路线图:2->3->1->5
最少通过传送门数:3
解题思路:
- 根据题设各个房间的传送门编号数据,获得从某个房间可以至其它房间的房间编号,用字典数据类型以链表方式存储:
# 根据列表用字典创建链表
def get_dict(num,rms):
dct = {i+1:[] for i in range(num)}
for i in range(num):
for j in range(num):
if i != j:
if set(rms[i]) & set(rms[j]) != set():
dct[i+1].append( j+1)
return dct
-
获得路线图
-
如果 b == a -> a 添加到路线图 path 列表中
-
如果 b in dct[a] -> a,b 添加到路线图 path 列表中
-
否则 将 房间 a 所能到达的房间编号,压入 stack 堆栈中
-
将 房间 a 存入记忆列表 memory 中
-
将 房间 a 存入路线图 path 列表中
-
遍历 堆栈 stack
6.1. 弹出 房间 a 能到达的第一个房间,并赋值给 a
6.2. 检查 这个房间是否已经检查过 a in memory
6.2.1. 如果已经检查过
6.2.2. 检查 堆栈 stack 是否为空
6.2.2.1. 如果堆栈不为空
弹出 房间 a 能到达的下一个房间,并赋值给 a
6.2.2.2. 否则
返回已经查到的路径图
6.2.3. 重复 6.2.
6.3.检查 房间 a 是否可以到达目标房间 b
6.3.1. 可以
添加房间 a 到路线图
添加路线 b 到路线图
返回 路线图 path
6.3.2. 不可以
将 a 可以到达的房间 压入堆栈 stack
6.4. 递归调用 2 获得路线图
# 获得路线图 def get_path(a,b): global stack, memory, path if b == a: path.append(a) return path if b in dct[a]: path.append(a) path.append(b) return path stack = dct[a] memory.append(a) path.append(a) while stack: a = stack.pop() while a in memory: if stack: a = stack.pop() else: return path if b in dct[a]: path.append(a) path.append(b) return path else: stack.extend(dct[a]) get_path(a,b)
- 主程序
- 输入房间数 num
- 输入传送门 rms
- 输入出发房间 a 到达房间 b
- 调用 get_dict(num,rms) 获得字典链表
- 定义全局变量
- 堆栈列表 stack
- 记忆列表 memory
- 路线列表 path
- 调用 get_path(a,b)
- 将结果赋值给变量 fdpath 前行路线图
- 重复5.定义全局变量
- 再次调用 get_path(b,a)
- 将结果赋值给变量 bkpath 后退路线图
- 比较两次计算结果,取长度最小路线图 minpath
- 打印输出路线图和经过的传送门数。
num = 5 rms = [{1,5},{2,3,8},{1,3,6},{4,2,6,9},{5,7}] a,b = 4,5 dct = get_dict(num,rms) stack = [] memory = [] path = [] get_path(a,b) fdpath = path.copy() dct = get_dict(num,rms) stack = [] memory = [] path = [] get_path(b,a) bkpath = path.copy() print(fdpath, bkpath) minPath = min(fdpath,bkpath, key=len) s = '' if minPath == fdpath: for i in minPath: s += f'{i}->' else: for i in reversed(minPath): s += f'{i}->' dct = get_dict(num,rms) print(f'各房间传送门编号:{rms}') print(f'从某个房间到其它房间的链表:{dct}') print(f'房间{a}至房间{b}的路线图:{s[:-2]}') print(f'最少通过传送门数:{len(minPath)-1}')
程序运行结果
[4, 2, 3, 1, 5] [5, 1, 3, 4]
各房间传送门编号:[{1, 5}, {8, 2, 3}, {1, 3, 6}, {9, 2, 4, 6}, {5, 7}]
从某个房间到其它房间的链表:{1: [3, 5], 2: [3, 4], 3: [1, 2, 4], 4: [2, 3], 5: [1]}
房间4至房间5的路线图:4->3->1->5
最少通过传送门数:3 - 主程序
-