障碍网格的哈密顿路径与Python递归极限
我试图在一个给定的网格中找到任何哈密顿路径,其中包含了不同节点上的障碍物。我的问题是我的代码已经运行了好几天了,还没有结束。虽然这个问题是NP完全问题,但从我所看到的情况来看,我不确定缺乏足够的时间是我的问题 在python中,我的方法是使用递归来执行深度优先搜索,搜索所有可能通过网格进行的左、右、上、下移动顺序。我研究过哈密顿路径问题的其他方法,但它们比我所做的更复杂,我不认为小网格需要它们 下面是我正在搜索的网格。0是开放节点,1是障碍物,S是起点障碍网格的哈密顿路径与Python递归极限,python,python-2.7,recursion,hamiltonian-cycle,Python,Python 2.7,Recursion,Hamiltonian Cycle,我试图在一个给定的网格中找到任何哈密顿路径,其中包含了不同节点上的障碍物。我的问题是我的代码已经运行了好几天了,还没有结束。虽然这个问题是NP完全问题,但从我所看到的情况来看,我不确定缺乏足够的时间是我的问题 在python中,我的方法是使用递归来执行深度优先搜索,搜索所有可能通过网格进行的左、右、上、下移动顺序。我研究过哈密顿路径问题的其他方法,但它们比我所做的更复杂,我不认为小网格需要它们 下面是我正在搜索的网格。0是开放节点,1是障碍物,S是起点 [0,0,0,0,0,0,0,0,0,0,
[0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,1,0,0,1,0,1,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,S]
[0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,1,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0,0,0,0]
下面是运行函数的当前网格的一个示例输出,1现在也表示访问的节点
[1, 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, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0]
[1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0]
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1]
[1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1]
然而,即使以每秒50000步的速度,代码似乎也从未停止检查右下角。例如,从未到达节点3,1和3,2处的两个0
这给我留下了一些问题:
这仅仅是NP难的一个标准症状吗,即使我只是尝试使用13x9网格?
我是否达到了python递归限制,导致代码无休止地重新运行相同的DFS分支?
还是我还遗漏了什么
这是我的搜索方法的简化版本:
#examines options of steps at current marker cell and iterates path attempts
def tryStep():
global path #list of grid movements
global marker #current cell in examination
set marker to traveled
if whole grid is Traveled:
print path data
end program
#map is incomplete, advance a step
else:
if can move Up:
repeat tryStep()
if can move left:
repeat tryStep()
if can move down:
repeat tryStep()
if can move right:
repeat tryStep()
#Failure condition reached, must backup a step
set marker cell to untraveled
if length of path is 0:
print 'no path exists'
end program
last = path.pop()
if last == "up":
move marker cell down
if last == "left":
move marker cell right
if last == "down":
move marker cell up
if last == "right":
move marker cell left
return
因此,代码应该遍历网格中所有可能的路径,直到形成哈密顿路径。
以下是我正在运行的实际代码供参考:
'''
Created on Aug 30, 2014
@author: Owner
'''
#Search given grid for hamiltonian path
import datetime
#takes grid cord and returns value
def getVal(x,y):
global mapWidth
global mapHeight
global mapOccupancy
if (((x < mapWidth) and (x >-1)) and (y < mapHeight and y >-1)):
return mapOccupancy[y][x]
else:
#print "cell not in map"
return 1
return
#sets given coord cell value to visted
def travVal(x,y):
global mapWidth
global mapHeight
global mapOccupancy
if (((x < mapWidth) and (x >-1)) and ((y < mapHeight) and (y >-1)))== True:
mapOccupancy[y][x] = 1
else:
#print "cell not in map"
return 1
return
#sets given coord cell value to open
def clearVal(x,y):
if (((x < mapWidth) and (x > -1)) and ((y < mapHeight) and (y > -1)))==True:
mapOccupancy[y][x] = 0
else:
#print "cell not in map"
return 1
return
#checks if entire map has been traveled
def mapTraveled():
isFull = False
endLoop= False
complete = True
for row in mapOccupancy:
if endLoop ==True:
isFull = False
complete = False
break
for cell in row:
if cell == 0:
complete = False
endLoop = True
break
if complete == True:
isFull = True
return isFull
#examines options of steps at current marker cell and iterates path attempts
def tryStep():
global path
global marker
global goalCell
global timeEnd
global timeStart
global printCount
travVal(marker[0],marker[1])
printCount += 1
#only print current map Occupancy every 100000 steps
if printCount >= 100000:
printCount = 0
print ''
print marker
for row in mapOccupancy:
print row
if mapTraveled():
print 'map complete'
print "path found"
print marker
print path
for row in mapOccupancy:
print row
print timeStart
timeEnd= datetime.datetime.now()
print timeEnd
while True:
a=5
#if map is incomplete, advance a step
else:
#Upwards
if getVal(marker[0],marker[1]-1) == 0:
marker = [marker[0],marker[1]-1]
#print "step: " + str(marker[0])+' '+ str(marker[1])
path.append('up')
tryStep()
#left wards
if getVal(marker[0]-1,marker[1]) == 0:
marker = [marker[0]-1,marker[1]]
#print "step: " + str(marker[0])+' '+ str(marker[1])
path.append('left')
tryStep()
# down wards
if getVal(marker[0],marker[1]+1) == 0:
marker = [marker[0],marker[1]+1]
#print "step: " + str(marker[0])+' '+ str(marker[1])
path.append('down')
tryStep()
#right wards
if getVal(marker[0]+1,marker[1]) == 0:
marker = [marker[0]+1,marker[1]]
# print "step: " + str(marker[0])+' '+ str(marker[1])
path.append('right')
tryStep()
#Failure condition reached, must backup steps
clearVal(m[0],m[1])
last = path.pop()
#print 'backing a step from:'
#print last
if last == "up":
marker = [marker[0],marker[1]+1]
if last == "left":
marker = [marker[0]+1,marker[1]]
if last == "down":
marker = [marker[0],marker[1]-1]
if last == "right":
marker = [marker[0]-1,marker[1]]
return
if __name__ == '__main__':
global timeStart
timeStart = datetime.datetime.now()
print timeStart
global timeEnd
timeEnd= datetime.datetime.now()
global printCount
printCount = 0
global mapHeight
mapHeight = 9
global mapWidth
mapWidth =13
#occupancy grid setup
r0= [0,0,0,0,0,0,0,0,0,0,0,0,0]
r1= [0,0,0,0,0,0,1,0,0,0,0,0,0]
r2= [0,0,0,0,0,0,0,0,0,0,0,0,0]
r3= [0,0,0,1,0,0, 1 ,0,1,0,0,0,0]
r4= [0,0,0,0,0,0,0,0,0,0,0,0, 0]
r5= [0,0,0,0,0,0,0,0,0,0,0,0,0]
r6= [0,0,0,0,0,0,1,0,0,0,0,0,0]
r7= [0,0,0,0,0,0,0,0,0,0,0,0,0]
r8= [0,0,0,0,0,0,0,0,0,0,0,0,0]
global mapOccupancy
mapOccupancy = [r0,r1,r2,r3,r4,r5,r6,r7,r8]
#record of current trail attempt
global path
path = []
#marker for iterating through grid
global marker
start = [12,4]
#start =[0,2]
m = start
global goalCell
goalCell = [6,3]
print marker
tryStep()
#no path avalible if this point is reached
print'destination is unreachable'
print 'last path: '
for row in mapOccupancy:
print row
print path
print m
print mapOccupancy
print timeStart
timeEnd= datetime.datetime.now()
print timeEnd
快速且非常粗略的计算,给出问题复杂性的估计 总共有13*9==117个节点,其中5个是墙,剩下112个开放节点。每个开放节点有2到4个邻居,平均来说,它们有3个邻居,这实际上是低估了。这意味着您应该检查的路径数约为3^112≈ 2.7*10^53.
当然,有时您会更早地停止搜索,但估计仍然存在:路径数量巨大,因此使用蛮力回溯检查所有路径是没有意义的。如果达到递归限制,则会出现异常,因此,除非你悄悄地忽略这些,否则这里不应该出现这种情况。2^13*9似乎是一个非常粗略但合理的估计,估计有多少不同的可能路径。这是一个很大的数字。谢谢,很高兴知道。如果我在添加修剪方法,比如搜索孤立的单元格,是否有任何可能的估计?@user3412893可能有,但这是一个不同的问题,实际上不应该问堆栈溢出,而应该问堆栈溢出。