在网格中找到随机哈密顿路径的算法?

时间:2011-09-10 10:57:11

标签: algorithm graph-algorithm hamiltonian-cycle

我正在寻找一种能够在双向N * M网格中找到尽可能随机Hamiltonian path的高效算法。

有谁知道我在哪里可以找到,或者如何构建这样的算法?


我已经找到了一种有效的方法(见下图)。这里的最终结果是哈密顿循环。删除随机边缘将使其成为哈密尔顿路径。该算法是有效的,但不提供足够的随机性。这种方法总是让路径的起点和终点彼此相邻,而我希望将它们放在随机位置。 Space-filling curve http://img593.imageshack.us/img593/8060/sfc.png 图片取自http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.35.3648&rep=rep1&type=pdf

4 个答案:

答案 0 :(得分:5)

首先,从pdf文件中显示在图像上的算法不是Hamilton路径问题的解决方案,而是迷宫生成的解决方案,因为最终路径有几个分支。

要查找迷宫生成的算法,请参阅: https://en.wikipedia.org/wiki/Maze_generation_algorithm

现在,这是一个在N * M 2D网格上生成哈密顿路径的简单算法:

1)设N * M网格(例如,4 * 5):

O-O-O-O-O
| | | | |
O-O-O-O-O
| | | | |
O-O-O-O-O
| | | | |
O-O-O-O-O

2)让我们从东/北角开始,让我们为西方和东方创造一个简单的曲折:

O-O-O-O-O
|
O-O-O-O-O
        |
O-O-O-O-O
|        
O-O-O-O-O

现在我们有了哈密尔顿路径。

3)让我们搜索另一个前面的两个胶合边缘。它们是循环的开始和结束:

O-O-O-O-O
|        
O-OXO-O-O
        |
O-OXO-O-O
|        
O-O-O-O-O

4)确保环路内至少有一条边缘粘在环路外边缘,否则,请转到步骤3:

O-O-O-O-O
|        
O-OXO-O-O
        |
O-OXOxO-O
|        
O-O-OxO-O

5)快捷循环:

O-O-O-O-O
|        
O-O O-O-O
  | |   |
O-O OxO-O
|        
O-O-OxO-O

6)通过另外两个胶合边重新连接环:

O-O-O-O-O
|        
O-O O-O-O
  | |   |
O-O O O-O
|   | |  
O-O-O O-O

7)如果哈密尔顿路径没有足够随机化,请转到步骤3.

只有开始和结束才会移动。要使结束或开始随机化,您可以用另一种算法替换初始之字形:

  1. 选择四个角中的一个
  2. 搜索所有未访问过的邻居
  3. 如果没有邻居,则填写地图,否则转到步骤4
  4. 只保留在左侧或右侧(换句话说,沿着非访问区域的边界行走的邻居)中具有空白或访问过的单元格的邻居。
  5. 选择其中一个邻居,访问它并转到第2步
  6. 结果可能如下:

    O-O-O-O-O
            |
    O-O-O-O O
    |     | |
    O O-O O O
    |   | | |
    O-O-O O-O
    

    使用此算法,开始仍然在一个角落,但结束可以在任何地方。要随机化开始和结束,您可以应用一种算法,您可以在开始或结束时多次迭代。让我们开始吧:

    1)找到开始:

    |
    v
    O-O-O-O-O
            |
    O-O-O-O O
    |     | |
    O O-O O O
    |   | | |
    O-O-O O-O
    

    2)找到一个没有直接连接到起点的邻居(你总能在2D网格中找到一个):

      O-O-O-O-O
              |
    ->O-O-O-O O
      |     | |
      O O-O O O
      |   | | |
      O-O-O O-O
    

    3)从一开始(分别从头到尾)找到你到达的地方:

    O-O-O-O-O
            |
    OXO-O-O O
    |     | |
    O O-O O O
    |   | | |
    O-O-O O-O
    

    4)剪切此链接并在此点和开头之间创建一个链接:

    O-O-O-O-O
    |       |
    O O-O-O O
    |     | |
    O O-O O O
    |   | | |
    O-O-O O-O
    

    开始移动了两个单元格。开始和结束与棋盘一样,它们只能在具有相同颜色的表壳上移动。

    现在你的路径是完全随机的。

    这是Python中的整个算法。你可以在这里运行它: http://www.compileonline.com/execute_python3_online.php

    结果存储在一个记录两次的数组(self.gameGrid)中(带箭头和节点和行)。前两个粘合边称为置换,第二个称为交集

    #!/usr/local/bin/python3
    
    import random
    
    class CellRoom:
    
      def generateGame(self):
        ## Constants
        self.UNDEFINED = 0
        self.FROM_NOWHERE = 1
        self.FROM_NORTH = 2
        self.FROM_EAST = 3
        self.FROM_SOUTH = 4
        self.FROM_WEST = 5
    
        self.LEFT = 0
        self.RIGHT = 1
    
        self.GAME_WIDTH = random.randint(3, 20)
        self.GAME_HEIGHT = random.randint(3, 20)
    
        self.initGame()
    
        for i in range(100):
          self.permutate()
    
        ##self.logGameWithPath()
        ##self.logGameWithArrow()
        for i in range(50):
          self.start = self.moveExtremity(self.start)
        self.logGameWithPath()
        self.logGameWithArrow()
        self.verifyGame()
    
      ## Print the map of the game on the standard output.
      ## Do not show the orientation.
      def logGameWithPath(self):
        print ('game width: ' + str(self.GAME_WIDTH))
        print ('game height: ' + str(self.GAME_HEIGHT))
        print ('Start [x=' + str(self.start[1]) + ', y=' + str(self.start[0]) + ']')
    
        gameText = ''
    
        for i in range(len(self.gameGrid)):
          for j in range(len(self.gameGrid[i])):
            if (self.gameGrid[i][j] == self.FROM_NORTH) or ((i > 0) and (self.gameGrid[i - 1][j] == self.FROM_SOUTH)):
              gameText = gameText + ' |'
            else:
              gameText = gameText + '  '
          gameText = gameText + ' \n'
          for j in range(len(self.gameGrid[i])):
            if (self.gameGrid[i][j] == self.FROM_WEST) or ((j > 0) and (self.gameGrid[i][j - 1] == self.FROM_EAST)):
              gameText = gameText + '-O'
            else:
              gameText = gameText + ' O'
          gameText = gameText + ' \n'
    
        for j in range(len(self.gameGrid[i])):
          gameText = gameText + '  '
        gameText = gameText + ' \n'
    
        print (gameText)
    
      ## Print the map of the game on the standard output.
      ## It shows the orientation.
      def logGameWithArrow(self):
        gameText = ''
    
        for gameLine in self.gameGrid:
          for j in gameLine:
            if j == self.FROM_NOWHERE:
              gameText = gameText + 'X'
            elif j == self.FROM_NORTH:
              gameText = gameText + 'V'
            elif j == self.FROM_EAST:
              gameText = gameText + '('
            elif j == self.FROM_SOUTH:
              gameText = gameText + '^'
            elif j == self.FROM_WEST:
              gameText = gameText + ')'
          gameText = gameText + '\n'
    
        print (gameText)
    
      ## Generate a new map with an extremity (ex. start point) at another place.
      ## It receives and returns a valid map.
      def moveExtremity(self, extremity):
        ## Search the points.
        possibleNewOrigins = []
        if ((extremity[0] < self.GAME_HEIGHT - 1) and (self.gameGrid[extremity[0] + 1][extremity[1]] != self.FROM_NORTH)):
          possibleNewOrigins.append(self.FROM_NORTH)
          besidePoint = [extremity[0] + 1, extremity[1]]
        elif ((extremity[1] > 0) and (self.gameGrid[extremity[0]][extremity[1] - 1] != self.FROM_EAST)):
          possibleNewOrigins.append(self.FROM_EAST)
          besidePoint = [extremity[0], extremity[1] - 1]
        elif ((extremity[0] > 0) and (self.gameGrid[extremity[0] - 1][extremity[1]] != self.FROM_SOUTH)):
          possibleNewOrigins.append(self.FROM_SOUTH)
          besidePoint = [extremity[0] - 1, extremity[1]]
        elif ((extremity[1] < self.GAME_WIDTH - 1) and (self.gameGrid[extremity[0]][extremity[1] + 1] != self.FROM_WEST)):
          possibleNewOrigins.append(self.FROM_WEST)
          besidePoint = [extremity[0], extremity[1] + 1]
    
        besidePointNewOrigin = possibleNewOrigins[random.randint(0, len(possibleNewOrigins) - 1)]
    
        if besidePointNewOrigin == self.FROM_NORTH:
          besidePoint = [extremity[0] + 1, extremity[1]]
        elif besidePointNewOrigin == self.FROM_EAST:
          besidePoint = [extremity[0], extremity[1] - 1]
        elif besidePointNewOrigin == self.FROM_SOUTH:
          besidePoint = [extremity[0] - 1, extremity[1]]
        elif besidePointNewOrigin == self.FROM_WEST:
          besidePoint = [extremity[0], extremity[1] + 1]
    
        ##print ('New start: [' + str(extremity[0]) + ', ' + str(extremity[1]) + ']')
        ##print ('besidePoint: [' + str(besidePoint[0]) + ', ' + str(besidePoint[1]) + ']')
    
        ## Search the new extremity
        if self.gameGrid[besidePoint[0]][besidePoint[1]] == self.FROM_NORTH:
          newExtremity = [besidePoint[0] - 1, besidePoint[1]]
        elif self.gameGrid[besidePoint[0]][besidePoint[1]] == self.FROM_EAST:
          newExtremity = [besidePoint[0], besidePoint[1] + 1]
        elif self.gameGrid[besidePoint[0]][besidePoint[1]] == self.FROM_SOUTH:
          newExtremity = [besidePoint[0] + 1, besidePoint[1]]
        elif self.gameGrid[besidePoint[0]][besidePoint[1]] == self.FROM_WEST:
          newExtremity = [besidePoint[0], besidePoint[1] - 1]
    
        ## Do the move.
        self.reversePath(extremity, newExtremity)
    
        self.gameGrid[besidePoint[0]][besidePoint[1]] = besidePointNewOrigin
        self.gameGrid[newExtremity[0]][newExtremity[1]] = self.FROM_NOWHERE
        ##print ('extremity: [' + str(newExtremity[0]) + ', ' + str(newExtremity[1]) + ']')
    
        return newExtremity
    
      ## Rewrite the path on the map as the end was the start and vice versa.
      ## The end becomes undefined.
      def reversePath(self, start, end):
        currentPoint = start
        ##print ('start: [' + str(currentPoint[0]) + ', ' + str(currentPoint[1]) + ']')
        ##print ('end: [' + str(end[0]) + ', ' + str(end[1]) + ']')
        while (currentPoint[0] != end[0]) or (currentPoint[1] != end[1]):
          ##print ('currentPoint: [' + str(currentPoint[0]) + ', ' + str(currentPoint[1]) + ']')
          ## We search the next point, not the point we just have reversed
          if (currentPoint[0] < self.GAME_HEIGHT - 1) and (self.gameGrid[currentPoint[0] + 1][currentPoint[1]] == self.FROM_NORTH) and (self.gameGrid[currentPoint[0]][currentPoint[1]] != self.FROM_SOUTH):
            self.gameGrid[currentPoint[0]][currentPoint[1]] = self.FROM_SOUTH
            currentPoint[0] = currentPoint[0] + 1
          elif (currentPoint[1] > 0) and (self.gameGrid[currentPoint[0]][currentPoint[1] - 1] == self.FROM_EAST) and (self.gameGrid[currentPoint[0]][currentPoint[1]] != self.FROM_WEST):
            self.gameGrid[currentPoint[0]][currentPoint[1]] = self.FROM_WEST
            currentPoint[1] = currentPoint[1] - 1
          elif (currentPoint[0] > 0) and (self.gameGrid[currentPoint[0] - 1][currentPoint[1]] == self.FROM_SOUTH) and (self.gameGrid[currentPoint[0]][currentPoint[1]] != self.FROM_NORTH):
            self.gameGrid[currentPoint[0]][currentPoint[1]] = self.FROM_NORTH
            currentPoint[0] = currentPoint[0] - 1
          elif (currentPoint[1] < self.GAME_WIDTH - 1) and (self.gameGrid[currentPoint[0]][currentPoint[1] + 1] == self.FROM_WEST) and (self.gameGrid[currentPoint[0]][currentPoint[1]] != self.FROM_EAST):
            self.gameGrid[currentPoint[0]][currentPoint[1]] = self.FROM_EAST
            currentPoint[1] = currentPoint[1] + 1
        ##print ('reversePath: [' + str(currentPoint[0]) + ', ' + str(currentPoint[1]) + ']')
        self.gameGrid[currentPoint[0]][currentPoint[1]] = self.UNDEFINED
    
      ## Check that we go on every cell.
      def verifyGame(self):
        moveCount = 0
        currentPoint = [self.start[0], self.start[1]]
    
        isEnd = 0
        while (isEnd == 0):
          if (currentPoint[0] < self.GAME_HEIGHT - 1) and (self.gameGrid[currentPoint[0] + 1][currentPoint[1]] == self.FROM_NORTH):
            currentPoint[0] = currentPoint[0] + 1
          elif (currentPoint[1] > 0) and (self.gameGrid[currentPoint[0]][currentPoint[1] - 1] == self.FROM_EAST):
            currentPoint[1] = currentPoint[1] - 1
          elif (currentPoint[0] > 0) and (self.gameGrid[currentPoint[0] - 1][currentPoint[1]] == self.FROM_SOUTH):
            currentPoint[0] = currentPoint[0] - 1
          elif (currentPoint[1] < self.GAME_WIDTH - 1) and (self.gameGrid[currentPoint[0]][currentPoint[1] + 1] == self.FROM_WEST):
            currentPoint[1] = currentPoint[1] + 1
          else:
            isEnd = 1
    
          if isEnd == 0:
            moveCount = moveCount + 1
    
        ## The number of moves should equal to the size of the map minus one cell because we don't arrive on the start
        if moveCount == ((self.GAME_HEIGHT * self.GAME_WIDTH) - 1):
          print ('OK')
        else:
          print ('ko!!!')
    
      ## Fill the map with void data.
      def initGame(self):
        self.gameGrid = []
        for i in range(self.GAME_HEIGHT):
          gameLine = []
          for j in range(self.GAME_WIDTH):
            gameLine.append(self.UNDEFINED)
    
          self.gameGrid.append(gameLine)
    
        self.initComplexMap()
    
      ## Create a valid simple map.
      ## It uses a complex algorithm.
      def initComplexMap(self):
        startPoint = random.randint(0, 3)
        if startPoint == 0:
          self.start = [0, 0]
        elif startPoint == 1:
          self.start = [0, self.GAME_WIDTH - 1]
        elif startPoint == 2:
          self.start = [self.GAME_HEIGHT - 1, 0]
        elif startPoint == 3:
          self.start = [self.GAME_HEIGHT - 1, self.GAME_WIDTH - 1]
    
        self.gameGrid[self.start[0]][self.start[1]] = self.FROM_NOWHERE
        currentPoint = [self.start[0], self.start[1]]
    
        while ((0 < currentPoint[0]) and (self.gameGrid[currentPoint[0] - 1][currentPoint[1]] == self.UNDEFINED)) or ((currentPoint[0] < self.GAME_HEIGHT - 1) and (self.gameGrid[currentPoint[0] + 1][currentPoint[1]] == self.UNDEFINED)) or ((0 < currentPoint[1]) and (self.gameGrid[currentPoint[0]][currentPoint[1] - 1] == self.UNDEFINED)) or ((currentPoint[1] < self.GAME_WIDTH - 1) and (self.gameGrid[currentPoint[0]][currentPoint[1] + 1] == self.UNDEFINED)):
          possibilities = []
          if ((0 < currentPoint[0]) and (self.gameGrid[currentPoint[0] - 1][currentPoint[1]] == self.UNDEFINED)) and (((0 == currentPoint[1]) or (self.gameGrid[currentPoint[0] - 1][currentPoint[1] - 1] != self.UNDEFINED)) or ((currentPoint[1] == self.GAME_WIDTH - 1) or (self.gameGrid[currentPoint[0] - 1][currentPoint[1] + 1] != self.UNDEFINED))):
            possibilities.append([currentPoint[0] - 1, currentPoint[1], self.FROM_SOUTH])
    
          if ((currentPoint[0] < self.GAME_HEIGHT - 1) and (self.gameGrid[currentPoint[0] + 1][currentPoint[1]] == self.UNDEFINED)) and (((0 == currentPoint[1]) or (self.gameGrid[currentPoint[0] + 1][currentPoint[1] - 1] != self.UNDEFINED)) or ((currentPoint[1] == self.GAME_WIDTH - 1) or (self.gameGrid[currentPoint[0] + 1][currentPoint[1] + 1] != self.UNDEFINED))):
            possibilities.append([currentPoint[0] + 1, currentPoint[1], self.FROM_NORTH])
    
          if ((0 < currentPoint[1]) and (self.gameGrid[currentPoint[0]][currentPoint[1] - 1] == self.UNDEFINED)) and (((0 == currentPoint[0]) or (self.gameGrid[currentPoint[0] - 1][currentPoint[1] - 1] != self.UNDEFINED)) or ((currentPoint[0] == self.GAME_HEIGHT - 1) or (self.gameGrid[currentPoint[0] + 1][currentPoint[1] - 1] != self.UNDEFINED))):
            possibilities.append([currentPoint[0], currentPoint[1] - 1, self.FROM_EAST])
    
          if ((currentPoint[1] < self.GAME_WIDTH - 1) and (self.gameGrid[currentPoint[0]][currentPoint[1] + 1] == self.UNDEFINED)) and (((0 == currentPoint[0]) or (self.gameGrid[currentPoint[0] - 1][currentPoint[1] + 1] != self.UNDEFINED)) or ((currentPoint[0] == self.GAME_HEIGHT - 1) or (self.gameGrid[currentPoint[0] + 1][currentPoint[1] + 1] != self.UNDEFINED))):
            possibilities.append([currentPoint[0], currentPoint[1] + 1, self.FROM_WEST])
    
          possibility = possibilities.pop(random.randint(0, len(possibilities) - 1))
          currentPoint = [possibility[0], possibility[1]]
          self.gameGrid[possibility[0]][possibility[1]] = possibility[2]
    
      ## Create a valid simple map.
      ## It uses a basic algorithm.
      def initSimpleMap(self):
        direction = self.RIGHT
    
        if random.randint(0, 1) == 0:
          for i in range(self.GAME_HEIGHT):
            if direction == self.RIGHT:
              self.gameGrid[i][0] = self.FROM_NORTH
              for j in range(1, self.GAME_WIDTH):
                self.gameGrid[i][j] = self.FROM_WEST
              direction = self.LEFT
            else:
              for j in range(self.GAME_WIDTH - 1):
                self.gameGrid[i][j] = self.FROM_EAST
              self.gameGrid[i][self.GAME_WIDTH - 1] = self.FROM_NORTH
              direction = self.RIGHT
    
            self.gameGrid.append(gameLine)
    
          self.gameGrid[0][0] = self.FROM_NOWHERE
        else:
          for j in range(self.GAME_WIDTH):
            if direction == self.RIGHT:
              self.gameGrid[0][j] = self.FROM_WEST
              for i in range(1, self.GAME_HEIGHT):
                self.gameGrid[i][j] = self.FROM_NORTH
              direction = self.LEFT
            else:
              for i in range(self.GAME_HEIGHT - 1):
                self.gameGrid[i][j] = self.FROM_SOUTH
              self.gameGrid[self.GAME_HEIGHT - 1][j] = self.FROM_WEST
              direction = self.RIGHT
    
          self.gameGrid[0][0] = self.FROM_NOWHERE
    
      ## Search all the possible permutations.
      ## It doesn't affect the map.
      def listPermutation(self):
        self.permutableZones = []
        for i in range(self.GAME_HEIGHT - 1):
          for j in range(self.GAME_WIDTH - 1):
            if (self.gameGrid[i + 1][j] == self.FROM_NORTH) and (self.gameGrid[i][j + 1] == self.FROM_SOUTH):
              self.permutableZones.append([[i + 1, j], [i, j + 1]])
            elif (self.gameGrid[i][j] == self.FROM_SOUTH) and (self.gameGrid[i + 1][j + 1] == self.FROM_NORTH):
              self.permutableZones.append([[i, j], [i + 1, j + 1]])
            elif (self.gameGrid[i][j] == self.FROM_EAST) and (self.gameGrid[i + 1][j + 1] == self.FROM_WEST):
              self.permutableZones.append([[i, j], [i + 1, j + 1]])
            elif (self.gameGrid[i][j + 1] == self.FROM_WEST) and (self.gameGrid[i + 1][j] == self.FROM_EAST):
              self.permutableZones.append([[i, j + 1], [i + 1, j]])
    
      ## Permutate the connection of path.
      ## It receives and returns a valid map.
      def permutate(self):
        self.listPermutation()
    
        if len(self.permutableZones) > 0:
          permutation = self.permutableZones.pop(random.randint(0, len(self.permutableZones) - 1))
          start = permutation[0]
          end = permutation[1]
          ##print ('Entry of the loop: (' + str(start[0]) + ', ' + str(start[1]) + ')')
          ##print ('Exit of the loop: (' + str(end[0]) + ', ' + str(end[1]) + ')')
          if self.isLoop(end, start):
            self.findPermutation(start, end)
          else:
            end = permutation[0]
            start = permutation[1]
            ## Assertion
            if not self.isLoop(end, start):
              print ('Wrong!')
            self.findPermutation(start, end)
    
      ## It doesn't affect the map.
      def isInLoop(self, searchedPoint):
        found = False
        for point in self.currentLoop:
          if (searchedPoint[0] == point[0]) and (searchedPoint[1] == point[1]):
            found = True
    
        return found
    
      ## It doesn't affect the map.
      def isLoop(self, originalPoint, destination):
        self.currentLoop = []
    
        point = []
        point.append(originalPoint[0])
        point.append(originalPoint[1])
        self.currentLoop.append([originalPoint[0], originalPoint[1]])
        while ((point[0] != destination[0]) or (point[1] != destination[1])) and (self.gameGrid[point[0]][point[1]] != self.FROM_NOWHERE):
          ##print ('Loop point: (' + str(point[0]) + ', ' + str(point[1]) + ')')
          newY = point[0]
          newX = point[1]
          if self.gameGrid[point[0]][point[1]] == self.FROM_SOUTH:
            newY = point[0] + 1
          elif self.gameGrid[point[0]][point[1]] == self.FROM_NORTH:
            newY = point[0] - 1
          elif self.gameGrid[point[0]][point[1]] == self.FROM_WEST:
            newX = point[1] - 1
          elif self.gameGrid[point[0]][point[1]] == self.FROM_EAST:
            newX = point[1] + 1
          point[0] = newY
          point[1] = newX
          self.currentLoop.append([newY, newX])
    
        return ((point[0] == destination[0]) and (point[1] == destination[1]))
    
      ## Permutate the connections of path.
      ## It receives and returns a valid map.
      def findPermutation(self, start, end):
        self.findIntersections()
        if len(self.intersections) > 0:
          self.modifyIntersection(start, end)
    
      ## Permutate the connections of path.
      ## It doesn't affect the map.
      def findIntersections(self):
        self.intersections = []
        for i in range(1, len(self.currentLoop) - 1):
          point = self.currentLoop[i]
          if self.gameGrid[point[0]][point[1]] == self.FROM_NORTH:
            if (0 < point[1]) and (self.gameGrid[point[0] - 1][point[1] - 1] == self.FROM_SOUTH) and not self.isInLoop([point[0] - 1, point[1] - 1]):
              self.intersections.append([[point[0], point[1]], [point[0] - 1, point[1] - 1]])
            elif (point[1] < self.GAME_WIDTH - 1) and (self.gameGrid[point[0] - 1][point[1] + 1] == self.FROM_SOUTH) and not self.isInLoop([point[0] - 1, point[1] + 1]):
              self.intersections.append([[point[0], point[1]], [point[0] - 1, point[1] + 1]])
    
          elif self.gameGrid[point[0]][point[1]] == self.FROM_SOUTH:
            if (0 < point[1]) and (self.gameGrid[point[0] + 1][point[1] - 1] == self.FROM_NORTH) and not self.isInLoop([point[0] + 1, point[1] - 1]):
              self.intersections.append([[point[0], point[1]], [point[0] + 1, point[1] - 1]])
            elif (point[1] < self.GAME_WIDTH - 1) and (self.gameGrid[point[0] + 1][point[1] + 1] == self.FROM_NORTH) and not self.isInLoop([point[0] + 1, point[1] + 1]):
              self.intersections.append([[point[0], point[1]], [point[0] + 1, point[1] + 1]])
    
          elif self.gameGrid[point[0]][point[1]] == self.FROM_WEST:
            if (0 < point[0]) and (self.gameGrid[point[0] - 1][point[1] - 1] == self.FROM_EAST) and not self.isInLoop([point[0] - 1, point[1] - 1]):
              self.intersections.append([[point[0], point[1]], [point[0] - 1, point[1] - 1]])
            elif (point[0] < self.GAME_HEIGHT - 1) and (self.gameGrid[point[0] + 1][point[1] - 1] == self.FROM_EAST) and not self.isInLoop([point[0] + 1, point[1] - 1]):
              self.intersections.append([[point[0], point[1]], [point[0] + 1, point[1] - 1]])
    
          elif self.gameGrid[point[0]][point[1]] == self.FROM_EAST:
            if (0 < point[0]) and (self.gameGrid[point[0] - 1][point[1] + 1] == self.FROM_WEST) and not self.isInLoop([point[0] - 1, point[1] + 1]):
              self.intersections.append([[point[0], point[1]], [point[0] - 1, point[1] + 1]])
            elif (point[0] < self.GAME_HEIGHT - 1) and (self.gameGrid[point[0] + 1][point[1] + 1] == self.FROM_WEST) and not self.isInLoop([point[0] + 1, point[1] + 1]):
              self.intersections.append([[point[0], point[1]], [point[0] + 1, point[1] + 1]])
    
      ## Permutate the connections of path.
      ## It receives and returns a valid map.
      def modifyIntersection(self, start, end):
        ##self.logGameWithPath()
        ##self.printGameOld()
        intersection = self.intersections[random.randint(0, len(self.intersections) - 1)]
        ## Disconnect the loop
        self.modifyPath([start, end])
        ## Reconnect the loop
        self.modifyPath(intersection)
    
      ## Change the connections on the map.
      def modifyPath(self, intersection):
        ##print ('modifyPath: (' + str(intersection[0][0]) + ', ' + str(intersection[0][1]) + ') with (' + str(intersection[1][0]) + ', ' + str(intersection[1][1]) + ')')
        firstPoint = self.gameGrid[intersection[0][0]][intersection[0][1]]
        secondPoint = self.gameGrid[intersection[1][0]][intersection[1][1]]
    
        if (self.gameGrid[intersection[0][0]][intersection[0][1]] == self.FROM_NORTH) or (self.gameGrid[intersection[0][0]][intersection[0][1]] == self.FROM_SOUTH):
          if (intersection[0][1] < intersection[1][1]):
            firstPoint = self.FROM_EAST
            secondPoint = self.FROM_WEST
          else:
            firstPoint = self.FROM_WEST
            secondPoint = self.FROM_EAST
        if (self.gameGrid[intersection[0][0]][intersection[0][1]] == self.FROM_EAST) or (self.gameGrid[intersection[0][0]][intersection[0][1]] == self.FROM_WEST):
          if (intersection[0][0] < intersection[1][0]):
            firstPoint = self.FROM_SOUTH
            secondPoint = self.FROM_NORTH
          else:
            firstPoint = self.FROM_NORTH
            secondPoint = self.FROM_SOUTH
    
        self.gameGrid[intersection[0][0]][intersection[0][1]] = firstPoint
        self.gameGrid[intersection[1][0]][intersection[1][1]] = secondPoint
    
    cellRoom = CellRoom()
    cellRoom.generateGame()
    

答案 1 :(得分:1)

足够随机性很一般, 你应该有一些基准测试,最有名的eucleadian TSP算法有3/2近似值(Christofides algorithm),它使用MST(就像你提到的算法那样是2近似),正如你在{{3}中看到的那样发现最佳PTAS的运行时间取决于(n log n)^ f(c,2)对于c> 1。 0(在你的样本的2维空间中)近似为(1 + 1 / c),并且具有常数因子的TSP的最佳近似值为wiki(最近发现),但所有这些都使用逻辑方式,有一些随机的用法,但它不会导致所有的东西都随机选择。如果你只是想随机使用,你可以使用3/2 - 1/500 algorithm,它更随机但是看Random Walk以获得更好的性能和随机性。

答案 2 :(得分:1)

本文介绍了一种方法:

Oberdorf,R。; Ferguson,A。; Jacobsen,J.L。; Kondev,J。 - Secondary Structures in Long Compact Polymers(arXiv.org)

该方法大致由以下内容组成:以锯齿形图案(网格上的非随机哈密顿路径)开始,并重复应用转换(称为“反咬”)到路径。 backbite包括从一个端点A添加一个边到另一个A连接到的相邻顶点B(从而创建一个循环),然后删除在B中开始的不是刚刚添加的边的边。这会导致一个循环(总会有一个循环导致一个循环而不是刚刚添加的循环)。

作者添加了一些条件来获得粗略的均匀性(包括估计应用反咬移动的次数)。文中详述。

作者还凭经验证明,他们的方法生成相邻端点的概率与均匀随机哈密顿路径中的理论概率近似匹配。

这里有一个JavaScript算法实现:Hamiltonian Path Generator

答案 3 :(得分:-1)

您可以从您提到的方法开始,找到哈密尔顿路径。要进一步随机化解决方案,您可以按照wiki中的说明开始旋转边缘。更频繁地这样做会使解决方案更加随机。旋转随机边N * M次使算法保持在有效域中,同时使找到的哈密顿路径更随机。