通过拥有迷宫房屋(二维)的列表,我如何使用字典创建有向图

发布于 2024-10-13 04:05:58 字数 44 浏览 3 评论 0原文

我只能做一个无向图。不知道如何制作定向的。

有什么想法吗?

I can only make an undirected graph. no idea on how i can make a directed one.

Any idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

初雪 2024-10-20 04:05:58

对于冗长的帖子表示歉意。我有时间在火车上消磨时间。

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

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

查找

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

  1. 每个
  2. 邻居的邻居(顶部、底部、左侧、右侧):
    • 如果不是可能的路径,则忽略
    • 如果我们之前处理过这个节点,则忽略
    • 否则,将此节点添加为边缘并将其推送到队列(不是堆栈,稍后会详细介绍)以进行进一步处理
  3. 每个节点队列/堆栈中的节点,从步骤 1 开始重复。

(参见下面的示例实现)

此时,您将得到一个 有向无环图 (DAG),起始节点位于树的顶部,结束节点作为叶子之一。此时解决这个问题很容易。请参阅有关解决以图形表示的迷宫的答案

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

堆栈还是队列?

请注意,使用堆栈(先进后出)意味着以 深度优先< /a> 方式,使用队列(先进先出)会导致 广度优先 方法。

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

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

如果路径是深度优先遍历的并且在分支 a 处,您碰巧会采取a->e 之前的 a->b 路径,最终会得到图表:

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

但是,使用广度优先方法,a->e 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

Apologies for the rather long winded post. I had time to kill on the train.

I'm guessing what you're after is a directed graph representing all paths leading away from your starting position (as opposed to a graph representation of the maze which once can use to solve arbitrary start/end positions).

(No offence meant, but) this sounds like homework, or at least, a task that is very suitable for homework. With this in mind, the following solution focuses on simplicity rather than performance or elegance.

Approach

One straight-forward way to do this would be to first store your map in a more navigable format, then, beginning with the start node do the following:

  1. look up neighbours (top, bottom, left, right)
  2. for each neighbour:
    • if it is not a possible path, ignore
    • if we have processed this node before, ignore
    • else, add this node as an edge and push it a queue (not a stack, more on this later) for further processing
  3. for each node in the queue/stack, repeat from step 1.

(See example implementation below)

At this point, you'll end up with a directed acyclic graph (DAG) with the starting node at the top of the tree and end node as one of the leaves. Solving this would be easy at this point. See this answer on solving a maze representing as a graph.

A possible optimisation when building the graph would be to stop once the end point is found. You'll end up with an incomplete graph, but if you're only concerned about the final solution this doesn't matter.

stack or queue?

Note that using a stack (first in last out) would mean building the graph in a depth-first manner, while using a queue (first in first out) would result in a breadth-first approach.

You would generally want to use a queue (breadth first if the intention is to look for the shortest path. Consider the following map:

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

If the path is traversed depth-first and at branch a you happen take the a->b path before a->e, you end up with the graph:

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

However, using a breadth-first approach the a->e path would come across node d earlier, resulting in a shorter graph and a better solution:

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

Example code

Sample input provided:

..........
#########.
..........
.#########
......#...
#####...#.
##...####.
##.#......
...#######

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

DISCLAIMER: The following code is written for clarity, not speed. It is not fully tested so there is no guarantee of correctness but it should give you an idea of what is possible.

We assumes that the input file is formatted consistently. Most error checking left out for brevity.

# 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
望笑 2024-10-20 04:05:58

此页面提供了一个关于使用 python 实现图形的很好的教程。从文章中,这是一个由字典表示的目录图的示例:

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

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

This page provides a nice tutorial on implementing graphs with python. From the article, this is an example of a directory graph represented by dictionary:

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

That said, you might also want to look into existing graph libraries such as NetworkX and igraph.

茶花眉 2024-10-20 04:05:58

由于您已经有了一个列表,请尝试创建邻接矩阵而不是字典。

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

Since you already have a list, try creating an Adjacency Matrix instead of a dictionary.

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

Then for any new edge from one house to another (or w/e the connection is)

directed_graph[from_house][to_house] = 1

and you're done. If there is an edge from house_a to house_b then directed_graph[house_a][house_b] == 1.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文