2014-09-07 4 views
1

여러 노드에 장애물이있는 주어진 격자에서 해밀턴 경로를 찾으려고합니다. 내 문제는 내 코드가 며칠 동안 실행되었으며 아직 끝나지 않은 것입니다. 이 문제는 NP-Complete 지역에 있지만, 내가 보는 것에서는 충분한 시간이 부족하다는 것이 내 문제인지 확신 할 수 없습니다.장애물 격자 및 파이썬 재귀 경로의 해밀턴 경로

필자의 접근 방식은 파이썬에서 재귀를 사용하여 그리드를 통해 만들 수있는 모든 왼쪽, 오른쪽, 위, 아래 움직임의 가능한 순서로 Depth First Search를 수행하는 것입니다. 나는 해밀턴 경로 문제에 대한 다른 방법을 연구했지만, 내가 한 일에 더 복잡했고, 작은 그리드가 필요하다고 생각하지 않았다.

다음은 내가 찾고있는 그리드이다. 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)에서의 2 개의 O는 결코 도달되지 않았다.

이렇게하면 다음과 같은 질문이 생깁니다. 13x9 그리드 만 시도하는 경우에도 NP-Hard의 표준 증상입니까? 파이썬 재귀 제한에 도달하여 내 코드가 끝내 동일한 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 
+0

재귀 한계에 도달하면 예외가 발생하므로 조용히 무시하지 않는 한 여기에 해당하지 않아야합니다. – uselpa

+0

2^(13 * 9)는 매우 거칠지 만 가능한 경로의 수에 대한 합리적인 추정으로 보입니다. 매우 큰 숫자입니다. – wookie919

답변

0

빠르고 매우 거친 계산, 문제의 복잡성의 추정을 제공 : 참고로 여기 내 실제 코드 내가 실행하고있다.

노드 수는 13*9 == 117 개이고 그 중 5 개는 벽이므로 112 개의 노드가 있습니다. 각각의 열린 노드는 2에서 4까지의 이웃을 가지고 있습니다. 평균적으로 이웃 노드는 3입니다 (사실 과소 평가입니다). 즉, 확인해야하는 경로의 수는 약 3^112 ≈ 2.7*10^53입니다.

물론 이전에 검색을 줄이는 경우가 있지만 추정치가 남아 있습니다. 경로 길이는 거대한이므로 무차별 역 추적을 사용하여 모든 경로를 검사하는 것은 의미가 없습니다.

+0

감사합니다. 알고있는 것이 좋습니다. 격리 된 셀을 검색하는 등의 가지 치기 메서드를 추가 할 경우 예상되는 결과가 있습니까? – user3412893

+0

@ user3412893 어쩌면 거기에,하지만 실제로는 스택 오버플로가 아닌 http://programmers.stackexchange.com에 질문해야하는 다른 질문입니다. –