[pygame解题]DFS深度优先回溯算法
结果:
运行中截图:
题目规则:
从红点出发,一笔连完所有格子,不能交叉,只能上下左右,不能斜向走。由此可以得出当路线长度等于粉色格子的个数时,题目有解。
状态树:
分析问题可以知道,此问题可以简化为一个子集树问题,在每一个点上都有上下左右几个方向可以生成几个叉枝,如下图。
回溯法:
回溯法中,首先需要明确下面三个概念:
(一)约束函数:约束函数是根据题意定出的。通过描述合法解的一般特征用于去除不合法的解,从而避免继续搜索出这个不合法解的剩余部分。因此,约束函数是对于任何状态空间树上的节点都有效、等价的。
(二)状态空间树:刚刚已经提到,状态空间树是一个对所有解的图形描述。树上的每个子节点的解都只有一个部分与父节点不同。
(三)扩展节点、活结点、死结点:所谓扩展节点,就是当前正在求出它的子节点的节点,在DFS中,只允许有一个扩展节点。活结点就是通过与约束函数的对照,节点本身和其父节点均满足约束函数要求的节点;死结点反之。由此很容易知道死结点是不必求出其子节点的(没有意义)。
python代码实现:
import os ,time,pygame,sys board = [[0, 1, 0, 1, 1, 1], [1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1], [0, 1, 1, 1, 0, 1], [1, 1, 1, 1, 1, 1], [1, 9, 1, 1, 1, 1]] #地图矩阵 def findHea(board): ''' 找到头部 ''' for x in range(len(board)): for y in range(len(board[x])): if(board[x][y]==9): return [x,y] def findC(board): ''' 找到障碍 ''' li=[] for x in range(len(board)): for y in range(len(board[x])): if(board[x][y]==0): li.append([x,y]) return li def jie(map): ''' 解出结果的条件 ''' jie = 0 for x in range(len(board)): for y in range(len(board[x])): if(board[x][y]==1): jie+=1 return jie def isok(x,y): ''' 判断合法性(约束函数) ''' try: if ((board[x][y]==0) or (x<0) or (x>len(board)) or (y<0) or (y>len(board[0]))): return False else: return True except : return False C=findC(board) def showMap(li): ''' 显示地图 ''' # board_C=board[:] board_C=[ [ "1" for o in range(6)] for i in range(6)] for n in li: board_C[n[0]][n[1]]="●" for n in C: board_C[n[0]][n[1]]="♦" board_C[li[-1][0]][li[-1][1]]="●" print("┏"+"━"*11+"┓") for c in board_C: c=[ " " if i=="1" else i for i in map(str,c)] print("┃"+(" ".join(c))+"┃") print("┗"+"━"*11+"┛") # showMap(luj) def luy(x,y): ''' 查找分支,生成子树 ''' luy=[] for u in [[-1,0],[1,0],[0,-1],[0,1]]:#上下左右 if isok(x+u[0],y+u[1]): # print(666) luy.append(u) return luy def show_map(map): map=map[:] b=100 for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() for x in range(len(map)): for y in range(len(map[x])): if(map[x][y]==1): rec_x=y*(b+1) rec_y=x*(b+1) # print(rec_x,rec_y) pygame.draw.rect(wind, (255,155,155), (rec_x,rec_y,b,b), 0) if(map[x][y]==9): rec_x=y*(b+1) rec_y=x*(b+1) # print(rec_x,rec_y) pygame.draw.rect(wind, (255,0,0), (rec_x,rec_y,b,b), 0) if(map[x][y]==0): rec_x=y*(b+1) rec_y=x*(b+1) # print(rec_x,rec_y) pygame.draw.rect(wind, (255,255,255), (rec_x,rec_y,b,b), 0) pygame.init() wind=pygame.display.set_mode([600,600]) pygame.display.set_caption("迷宫求解") background = pygame.Surface(wind.get_size()) background.fill((255, 255, 255)) def dfs(x,y,luj): ''' 回溯法 ''' lu=luy(x,y) for u in lu:#寻找分支 if(isok(x+u[0],y+u[1]) and [x+u[0],y+u[1]] not in luj): luj_o=luj[:] luj.append([x+u[0],y+u[1]]) # os.system("cls") wind.blit(background,(0,0))#pygame 绘制背景 show_map(board)#绘制地图 pygame.draw.lines(wind, (0,0,255), 0, [[i[1]*100+50,i[0]*100+50] for i in luj], 5)#绘制解法 pygame.display.update()#刷新屏幕 # time.sleep(0.5) # showMap(luj) if(len(luj)==jie): return luj ret=dfs(x+u[0],y+u[1],luj) if (type(ret)== type([])): return ret luj=luj_o[:] jie=jie(board)+1 # print(jie) luj=[findHea(board)]#初始化放入起点 #路径点列表 dfs_ok=dfs(findHea(board)[0],findHea(board)[1],luj) print(dfs_ok) while True: wind.blit(background,(0,0))#pygame 绘制背景 show_map(board)#绘制地图 pygame.draw.lines(wind, (0,0,255), 0, [[i[1]*100+50,i[0]*100+50] for i in dfs_ok], 5)#绘制解法 pygame.display.update()#刷新屏幕 pygame.quit()