1、笔试题目说明:
30道选择(包括单选和多选),占60分;2道编程题,占40分;
2、编程题解:
第一道编程题没怎么理解题意,重点在做第2道,根据当时的草稿及事后调通的代码,记录如下:
2.1 题目描述:迷宫问题(仅提取核心部分,有所简化)
给一个N*M的迷宫单元,其中的元素仅包含3个字符:“#”、“P”和“S”。其中“#”代表墙壁,表示不能通过;“S”代表单元迷宫的起点;“P”代表的是路,表示可以通行的道路。
若干个N*M的迷宫单元可以任意组合,迷宫单元之间只能进行左右拼接和上下拼接操作。并且,当大迷宫中的某个“S”被确定为起始点后,其他的“S”可被看作能够行走的道路,相当于“P”。
对于拼接之后的大迷宫,从某个起点“S”开始,可以无限地走下去(不会被墙壁阻隔,行走的方式只能是上下左右,不能斜着走),则认为这个迷宫单元是合法的。
输入:
第一行是两个正整数N和M,表示迷宫单元是N行M列(1≤N, M≤300)。之后N行,每一行是一个长度为M的字符串,如题所述,描述了一个迷宫单元。
输出:
如果这个迷宫单元是合法的,就输出“Yes”,否则输出“No”。
示例 1:
输入:
2 2
S#
#P
输出:
No
示例 2:
输入:
3 3
PPP
###
#S#
输出:
Yes
2.2 解题思路
(1)某个“S”被确定为起始位置之后,其他的“S”相当于“P”。因为起始位置是任意的,所以可以将问题简化为:迷宫单元仅包含两种情况的点:能通过的点(非墙)和不能通过的点(墙);这里分别用●和×来表示。
(2)合法的迷宫单元,组成的大迷宫可以无限地走下去,也就是始终有一条通路能够走出迷宫。对于无限地情况,不好用条件去限制,所以反过来判断有限的情况,也就是判断什么情况下是非法的迷宫单元。这里,根据示例绘制如下两种迷宫单元的组合,进行说明:
示例1:
如图,是4个2*2的迷宫单元组成的大迷宫,组合方式包括左右拼接和上下拼接,包含了所有的组合方式。
从示例结果来看,该迷宫单元非法;
从组合图来看,可以发现,每个 ● 周围(上下左右)都是墙壁,所有的通路都被堵死了。
示例2:
如图,是4个3*3的迷宫单元组成的大迷宫,包含了所有的组合方式。
从示例结果来看,该迷宫单元合法;
从组合图来看,可以很明显地发现,●周围有通路。
综合示例1和2的组合图及结果,可以发现:
(1)只要 ● 周围有通路,该迷宫单元组合出来的大迷宫就能够无限地走下去;
(2)从单个迷宫单元无法观测出●周围是否有通路,而4个迷宫单元上下左右拼接之后的大迷宫,则可以清楚地显示出●周围的通路情况;
(3)通过大迷宫判断出每个点的通路情况之后,只要迷宫单元中有一个点周围有通路,那么该迷宫单元即是合法的。
因此有如下解决方案:
(1)将4个迷宫单元进行上下左右拼接,组合成大迷宫;
(2)遍历大迷宫中的每个点(●和×),判断其周围是否有通路(此处要特别注意大迷宫4个角以及外围4个边行上的点的判断)。因此,还需要构造与大迷宫尺寸相等的数组,用来记录每个点的通路情况。
(3)对于迷宫中每个点的通路情况,若其周围都是墙(上下左右都是×),则说明通路被封死,可以用False表示;否则,只要周围有通路,则该点的即可走通,可以用True来表示。
2.3 代码实现如下:
# 判断是否能组合成合法迷宫
def check(ans, rows, cols):
recds = [[True] * cols for _ in range(rows)]
for i in range(rows):
for j in range(cols):
if ans[i][j] == '#': # 表示该点的路径被封死
recds[i][j] = False
continue
# 四个边角
if i == 0 and j == 0: # 左上角
if ans[i][j + 1] == '#' and ans[i + 1][j] == '#':
recds[i][j] = False
continue
if i == 0 and j == cols - 1: # 右上角
if ans[i + 1][j] == '#' and ans[i - 1][j] == '#':
recds[i][j] = False
continue
if i == rows - 1 and j == 0: # 左下角
if ans[i][j + 1] == '#' and ans[i - 1][j] == '#':
recds[i][j] = False
continue
if i == rows - 1 and j == cols - 1: # 右下角
if ans[i - 1][j] == '#' and ans[i][j - 1] == '#':
recds[i][j] = False
continue
# 四个边行
if i == 0:
if ans[i + 1][j] == '#' and ans[i][j + 1] == '#' \
and ans[i][j - 1] == '#':
recds[i][j] = False
continue
if i == rows - 1:
if ans[i - 1][j] == '#' and ans[i][j + 1] == '#' \
and ans[i][j - 1] == '#':
recds[i][j] = False
continue
if j == 0:
if ans[i - 1][j] == '#' and ans[i + 1][j] == '#'\
and ans[i][j+1] == '#':
recds[i][j] = False
continue
if j == cols - 1:
if ans[i-1][j] == '#' and ans[i + 1][j] == '#'\
and ans[i][j-1] == '#':
recds[i][j] = False
continue
# 其他有四个邻居的点
if 0 < i < rows - 1 and 0 < j < cols - 1:
if ans[i - 1][j] == '#' and ans[i + 1][j] == '#' and \
ans[i][j - 1] == '#' and ans[i][j + 1] == '#':
recds[i][j] = False
# 判断迷宫单元是否合法
flag = False
for i in range(rows // 2):
for j in range(cols // 2):
if recds[i][j]:
flag = True
break
return flag
pass
if __name__ == '__main__':
line = input().split(' ')
n, m = int(line[0]), int(line[1])
vals = []
for idx in range(n):
vals_temp = input()
vals.append(vals_temp * 2) # 左右拼接
vals = vals * 2 # 上下拼接
if check(vals, n * 2, m * 2):
print('Yes')
else:
print('no')
pass
以上,即是个人的解决思路。时间复杂度为O(NM)。
思路和代码比较暴力,还有需要改进和完善的地方。若有好的思路和方案,希望能够相互交流学习~