通过拥有迷宫房屋列表(2维),如何创建带有字典的有向图

时间:2011-01-19 16:48:15

标签: python graph directed-graph

我只能制作无向图。不知道如何制作有针对性的人。

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

为相当漫长的帖子道歉。我有时间在火车上杀人。

我猜你所追求的是一个有向图,表示远离起始位置的所有路径(而不是迷宫的图形表示,曾经可以用来解决任意开始/结束位置)。

(没有冒犯意味着,但是)这听起来像是家庭作业,或者至少是一项非常适合做作业的任务。考虑到这一点,以下解决方案侧重于简单而非性能或优雅。

方法

执行此操作的一种直接方法是首先以更可导航的格式存储地图,然后从开始节点开始执行以下操作:

  1. 查找邻居(上,下,左,右)
  2. 为每个邻居:
    • 如果不是可能的路径,请忽略
    • 如果我们之前已经处理过这个节点,请忽略
    • 否则,将此节点添加为边缘并将其推送到队列(不是堆栈,稍后将详细介绍)以进行进一步处理
  3. 对于队列/堆栈中的每个节点,从步骤1开始重复。
  4. (参见下面的示例实现)

    此时,您最终得到一个directed acyclic graph (DAG),其中起始节点位于树的顶部,而结束节点作为其中一个叶子。在这一点上解决这个问题很容易。请参阅this answer on solving a maze representing as a graph

    构建图形时可能的优化是在找到终点后停止。你最终会得到一个不完整的图表,但是如果你只关心最终的解决方案,这并不重要。

    堆栈还是队列?

    请注意,使用堆栈(倒数第一个)意味着以depth-first方式构建图形,而使用队列(先进先出)将导致breadth-first方法。

    您通常希望使用队列(如果目的是寻找最短路径,则首先使用广度。请考虑以下地图:

           START
    ########   ###### 
    ########   ######
    ### b    a ######  
    ###   ##   ######
    ###   ## e ######
    ### c    d ######
    ########   ######
    ########      END
    #################
    

    如果路径是深度优先遍历的,而在分支a,则会在a->b之前采用a->e路径,最后得到图表:

     START
       |
       a
      / \
     b   e   <-- end, since d already visited
     |
     c
     |
     d
      \
       END
    

    但是,使用广度优先方法,a->e路径会更早地遇到节点d,从而产生更短的图形和更好的解决方案:

     START
       |
       a
      / \
     b   e 
     |   |
     c   d
         |
        END
    

    示例代码

    提供的示例输入:

    ..........
    #########.
    ..........
    .#########
    ......#...
    #####...#.
    ##...####.
    ##.#......
    ...#######
    
    e = (0,0)
    s = (8,0)
    

    免责声明:为了清晰起见,编写了以下代码,而不是速度。它没有经过全面测试,因此无法保证其正确性,但它应该让您了解可能性。

    我们假设输入文件的格式一致。大多数错误检查都是为了简洁而遗漏的。

    # regex to extract start/end positions
    import re
    re_sepos = re.compile("""
        ^([se])\s* # capture first char (s or e) followed by arbitrary spaces
        =\s*        # equal sign followed by arbitrary spaces
        \(          # left parenthesis
        (\d+),(\d+) # capture 2 sets of integers separated by comma
        \)          # right parenthesis
    """, re.VERBOSE)
    
    def read_maze(filename):
        """
        Reads input from file and returns tuple (maze, start, end)
          maze : dict holding value of each maze cell { (x1,y1):'#', ... }
          start: start node coordinage (x1,y1)
          end  : end node coordinate (x2,y2)
        """
        # read whole file into a list
        f = open(filename, "r")
        data = f.readlines()
        f.close()
    
        # parse start and end positions from last 2 lines
        pos = {}
        for line in data[-2:]: 
            match = re_sepos.match(line)
            if not match:
                raise ValueError("invalid input file")
            c,x,y = match.groups() # extract values
            pos[c] = (int(x),int(y))
        try:
            start = pos["s"]
            end   = pos["e"]
        except KeyError:
            raise ValueError("invalid input file")
    
        # read ascii maze, '#' for wall '.' for empty slor 
        # store as maze = { (x1,y1):'#', (x2,y2):'.', ... }
        # NOTE: this is of course not optimal, but leads to a simpler access later 
        maze = {}
        for line_num, line in enumerate(data[:-3]): # ignore last 3 lines
            for col_num, value in enumerate(line[:-1]): # ignore \n at end
                maze[(line_num, col_num)] = value
    
        return maze, start, end
    
    def maze_to_dag(maze, start, end):
        """
        Traverses the map starting from start coordinate.
        Returns directed acyclic graph in the form {(x,y):[(x1,y1),(x2,y2)], ...}
        """
        dag = {}        # directed acyclic graph
        queue = [start] # queue of nodes to process
    
        # repeat till queue is empty
        while queue:
            x,y = queue.pop(0)      # get next node in queue
            edges = dag[(x,y)] = [] # init list to store edges
    
            # for each neighbour (top, bottom, left, right)
            for coord in ((x,y-1), (x,y+1), (x-1,y), (x+1,y)): 
                if coord in dag.keys(): continue   # visited before, ignore
    
                node_value = maze.get(coord, None) # Return None if outside maze
                if node_value == ".": # valid path found
                    edges.append(coord) # add as edge
                    queue.append(coord) # push into queue
    
                    # uncomment this to stop once we've found the end point
                    #if coord == end: return dag
    
        return dag
    
    if __name__ == "__main__":
        maze,start,end = read_maze("l4.txt")
        dag = maze_to_dag(maze, start, end)
        print dag
    

答案 1 :(得分:0)

This page提供了一个使用python实现图形的精彩教程。从文章中,这是一个由字典表示的目录图的示例:

graph = {'A': ['B', 'C'],
         'B': ['C', 'D'],
         'C': ['D'],
         'D': ['C'],
         'E': ['F'],
         'F': ['C']}

也就是说,您可能还想查看现有的图表库,例如NetworkXigraph

答案 2 :(得分:0)

由于您已有列表,请尝试创建Adjacency Matrix而不是字典。

list_of_houses = []
directed_graph = [][]
for i in xrange(len(list_of_houses)):
    for i in xrange(len(list_of_houses)):
        directed_graph[i][i] = 0

然后,从一个房子到另一个房子的任何新边缘(或连接是否是)

directed_graph[from_house][to_house] = 1

你已经完成了。如果有house_ahouse_b的边缘,那么directed_graph[house_a][house_b] == 1