【问题标题】:Convert array to nodes将数组转换为节点
【发布时间】:2013-11-09 22:11:45
【问题描述】:

首先我要说我对节点和图有非常基本的了解。

我的目标是为一个存储为数组的迷宫创建一个求解器。我确切地知道如何实现求解算法(我实际上正在实现其中的几个),但我的问题是,我对如何实现求解器将在每个空单元格中使用的节点感到非常困惑。

这是一个示例数组:

char maze[5][9] = 
        "#########",
        "#  #    #",
        "# ## ## #",
        "#     # #",
        "#########"

我的求解器从左上角开始,解决方案(退出)在右下角。

我已经阅读了有关节点如何工作以及如何实现图表的信息,所以我认为我需要这样做:

  • 起点会变成一个节点
  • 每个节点都有列和行号作为属性
  • 每个节点还将具有访问状态作为属性
  • 访问状态可以是visited, visited and leads to dead end, not visited
  • 每次访问节点时,每个直接相邻、空且未访问的单元格都会成为访问节点的子节点
  • 每个访问过的节点都被放在解决方案路径堆栈的顶部(并在地图上标记为“*”)
  • 导致死路的每个节点都从堆栈中删除(并在地图上标记为“~”)

完成的迷宫示例:

"#########",
"#*~#****#",
"#*##*##*#",
"#****~#*#",
"#########"

基本上我的问题是,我在这里用我的思维方式做了一些非常愚蠢的事情吗(因为我对节点真的没有经验)如果是的话,请你解释一下为什么?此外,如果可能的话,请提供其他网站来检查哪些实现了实际应用程序中的图表示例,以便我更好地掌握它。

【问题讨论】:

  • 迷宫中的每个开放(即非墙)位置都是一个节点。每个节点都应该有到它的邻居的边。一旦您将二维数组表示转换为通用图结构,您应该能够在其上实现您希望的任何图遍历算法。您可以通过多种方式对此进行优化(例如使用加权图),但这应该可以帮助您入门。
  • 我不打算对整个迷宫进行预处理,因为这样我会访问每个单元格,即使我不必这样做。我正在考虑制作节点。
  • 我想预处理不是必要的,但是根据你用来遍历迷宫的算法,它可能想知道有多少个节点先验。例如,大多数 Djisktra 算法的公式都假设您在开始时有一组节点和边。您的图形实际上以网格形式隐式表示,每个开放点都有节点,相邻开放点之间有边。如果您了解该映射并将其构建到代码中,您应该能够在此表示上实现您想要的任何图形算法。
  • FWIW,很久以前我写了一个直接在网格表示上工作的 BFS 实现。它甚至没有谈论节点和边缘,但这实际上就是它正在做的事情。你可以在这里找到它:spatula-city.org/~im14u2c/mso_contest/contest_9 节点-边缘关系被嵌入到代码中:当访问迷宫中的一个单元格时,它“知道”该单元格与其空间邻居相连。没有显式的边缘,只有隐式的。

标签: c++ arrays graph artificial-intelligence nodes


【解决方案1】:

答案实际上取决于您发现问题中最重要的内容。如果您正在搜索 效率速度 - 您添加的节点太多了。没必要这么多。

高效的方法

您的求解器只需要在路径的起点和终点以及地图上每个可能的拐角处的节点。像这样:

"#########",
"#oo#o  o#",
"# ## ## #",
"#o  oo#o#",
"#########"

没有真正需要测试地图上的其他地方 - 您要么必须步行穿过它们,要么甚至不需要费心测试。

如果它对你有帮助 - 我有一个模板 digraph 类,我为简单的图形表示而设计。写得不是很好,但非常适合展示可能的解决方案。

#include <set>
#include <map>

template <class _nodeType, class _edgeType>
class digraph
{
public:
    set<_nodeType> _nodes;
    map<pair<unsigned int,unsigned int>,_edgeType> _edges;
};

我使用这个类来使用 Dijkstra's 算法在塔防游戏中寻找路径。该表示应该足以满足任何其他算法。

节点可以是任何给定的类型——你最终可能会使用pair&lt;unsigned int, unsigned int&gt;_edges 将两个_nodes 连接到集合中的position

易于编码的方法

另一方面 - 如果您正在寻找一种易于实现的方法 - 您只需将数组中的每个可用空间都视为一个可能的节点。如果这就是您要查找的内容 - 无需设计图表,因为数组以完美的方式代表了问题。

你不需要专门的课程来解决这个问题。

bool myMap[9][5]; //the array containing the map info. 0 = impassable, 1 = passable
vector<pair<int,int>> route; //the way you need to go
pair<int,int> start = pair<int,int>(1,1); //The route starts at (1,1)
pair<int,int> end = pair<int,int>(7,3); //The road ends at (7,3)

route = findWay(myMap,start,end); //Finding the way with the algorithm you code

findWay 的原型是vector&lt;pair&lt;int,int&gt;&gt; findWay(int[][] map, pair&lt;int,int&gt; begin, pair&lt;int,int&gt; end),并实现了您想要的算法。在函数内部,您可能需要另一个 bool 类型的二维数组,用于指示测试的位置。

当算法找到路线时,通常你必须反向读取它,但我想这取决于算法。

在您的特定示例中,myMap 将包含:

bool myMap[9][5] = {0,0,0,0,0,0,0,0,0,
                    0,1,1,0,1,1,1,1,0,
                    0,1,0,0,1,0,0,1,0,
                    0,1,1,1,1,1,0,1,0,
                    0,0,0,0,0,0,0,0,0};

findWay 将返回一个包含(1,1),(1,2),(1,3),(2,3),(3,3),(4,3),(4,2),(4,1),(5,1),(6,1),(7,1),(7,2),(7,3)vector

【讨论】:

  • 是的,优化不是我的目标,我只是想找到实现 DFS 的最简单方法,然后是 BFS 和后来的 Dijkstra,这样我就可以习惯这 3 种算法了节点。因此,如果我正确地使用节点,我首先需要创建一个节点类,它将包含我的所有属性等?我不能只创建一个简单的结构吗?但我的主要问题是如何表示一个具有多个子节点的节点,我必须将它们中的每一个都添加到堆栈中。
  • @Powerbyte - 我给你的类代表了一个完整的图表。您不需要 node 类,但我猜它实际上会帮助您实现。如果您不理解我的代码,请阅读一些关于 templates 的内容。我稍后会更新答案,如果您愿意,请查看。
  • 感谢您的回复,我最终找到了另一种方法,无需图表,但您的方法肯定会在将来帮助我作为参考
猜你喜欢
  • 1970-01-01
  • 2016-08-21
  • 1970-01-01
  • 2014-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多