Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
障碍网格的哈密顿路径与Python递归极限_Python_Python 2.7_Recursion_Hamiltonian Cycle - Fatal编程技术网

障碍网格的哈密顿路径与Python递归极限

障碍网格的哈密顿路径与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,

我试图在一个给定的网格中找到任何哈密顿路径,其中包含了不同节点上的障碍物。我的问题是我的代码已经运行了好几天了,还没有结束。虽然这个问题是NP完全问题,但从我所看到的情况来看,我不确定缺乏足够的时间是我的问题

在python中,我的方法是使用递归来执行深度优先搜索,搜索所有可能通过网格进行的左、右、上、下移动顺序。我研究过哈密顿路径问题的其他方法,但它们比我所做的更复杂,我不认为小网格需要它们

下面是我正在搜索的网格。0是开放节点,1是障碍物,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,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可能有,但这是一个不同的问题,实际上不应该问堆栈溢出,而应该问堆栈溢出。