【问题标题】:Most efficient implementation for a complete undirected graph完整无向图的最有效实现
【发布时间】:2012-06-12 16:09:44
【问题描述】:

问题背景

我目前正在开发一个蚁群系统算法的框架。我想我会先尝试他们应用到的第一个问题:旅行推销员问题(TSP)。我将使用 C# 来完成这项任务。

所有 TSP 实例都将包含一个完整的无向图,其中每个边有 2 个不同的权重。

问题

到目前为止,我只使用邻接列表表示,但我读过它们仅推荐用于稀疏图。由于我不是最了解数据结构的人,所以我想知道实现无向完整图的最有效方法是什么?

如果需要,我可以提供更多详细信息。

感谢您的宝贵时间。

更新

重量说明。每条边都有两个与之关联的值:

  1. 两个城市之间的距离(d(i,j) = d(j,i) 两个方向的距离相同)
  2. 蚂蚁在特定边缘沉积的信息素量

运营。我将在图表上进行的操作的小总结:

  • 对于每个节点,该特定节点上的蚂蚁必须遍历与所有入射边关联的值

问题说明

蚁群优化算法可以“解决” TSP,因为这是它们首次应用于 .我说“求解”是因为它们属于称为元启发式优化的算法家族的一部分,因此它们从不保证返回最优解。

关于手头的问题:

  • 蚂蚁会知道如何完成一次旅行,因为每只蚂蚁都有记忆。
  • 每次蚂蚁访问一个城市时,它都会将该城市存储在它的内存中。
  • 每次蚂蚁考虑访问一个新城市时,它都会在其记忆中搜索并选择一条出边,前提是该边不会将其引导至已访问过的城市。
  • 当没有更多的边时蚂蚁可以选择它已经完成了一次旅行;此时,我们可以通过回溯它的记忆来回溯蚂蚁创建的旅程。

研究文章详情:Ant Colony System article

效率考虑

我更担心运行时间(速度)而不是内存。

【问题讨论】:

  • 没有单一的“最有效”表示。效率很大程度上取决于您要提供的操作列表以及它们被调用的频率。
  • 如果你有两个与边相关的权重,那么你就有一个有向图,而不是无向图(假设权重是针对不同方向的;否则它实际上只是一个(尽管很复杂)权重)
  • 如果术语不正确,请致歉:一个值表示两个城市之间的距离,第二个值表示蚂蚁在特定边缘上沉积的信息素数量。这仍然是无向的。
  • @Morat:最好通过澄清来编辑您的问题,而不是发表评论。很多人认为SO上的大多数cmets都是浪费时间,所以不要阅读它们。他们大多是对的,尽管这条评论是一颗罕见的珍珠。
  • 您的问题在某种程度上似乎自相矛盾。蚁群算法通常指的是演员直到到达那里才真正知道自己要去哪里的情况。没有办法让这种算法在算法上有效,因为你无法保证你的目的地。提出的问题是以最少的努力覆盖最多的区域。旅行推销员问题通常是指您有一个目的地系统并且问题是找到路线的情况。您能具体解释一下您要解决的问题吗?

标签: c# graph-theory heuristics ant-colony


【解决方案1】:

首先,有一个关于邻接列表与矩阵的一般指南here. 这是一个非常低级的非特定讨论,所以它可能不会告诉你任何你不知道的东西。

我认为,要点是:如果您经常发现自己需要回答“我需要确切知道节点 i 和节点 j 之间边缘的距离或信息素水平”的问题,那么您可能想要矩阵形式,因为该问题可以在 O(1) 时间内回答。

您确实提到需要迭代与节点相邻的边缘 - 这可能会带来一些聪明和微妙之处。如果您不关心迭代的顺序,那么您就不会关心数据结构。如果您非常关心顺序,并且您预先知道顺序,并且它永远不会改变,那么您可以将其直接编码到邻接列表中。如果您发现自己总是想要,例如最大或最小浓度的信息素,您可能想尝试一些更有条理的东西,比如优先队列。这真的取决于你在做什么类型的操作。

最后,我知道您提到您对速度比对内存更感兴趣,但我不清楚您将使用多少图形表示。如果只有一个,那你真的不在乎。但是,如果每只蚂蚁都在构建自己的图表示,那么您可能会比您想象的更关心,并且邻接表将让您携带不完整的图表示;不利的一面是,当蚂蚁在其边界进行探索时,构建表示需要时间。

最后,我知道您说您正在处理完整的图和 TSP,但值得考虑的是您是否曾经需要调整这些例程以适应可能的图上的其他问题,如果是这样,那又如何。

我倾向于使用邻接列表和/或更多结构,但我认为您不会找到一个清晰明了的答案。

【讨论】:

    【解决方案2】:

    既然你有一个完整的图表,我认为最好的表示是二维数组。

    public class Edge
    {
    //change types as appropriate
      public int Distance {get;set;}
      public int Pheromone {get;set;}
    }
    
    
    int numNodes;
    Edge[,] graph = new Edge[numNodes,numNodes];
    for(int i = 0; i < numNodes; i++)
    {
      for(int j = 0; j < numNodes; j++)
      {
        graph[i][j] = new Edge();
        //initialize Edge
      }
    }
    

    如果您有很多节点,并且不按此图中的索引“记住”节点,那么拥有一个将Node 映射到图中的索引的字典可能会有所帮助。进行反向查找也可能会有所帮助(List 将是此处的适当数据结构。这将使您能够获取 Node 对象(如果您有很多关于每个节点的信息要存储)基于该节点在图中的索引。

    【讨论】:

    • 我也考虑过这一点,但是以这种方式创建无向图会使主对角线下的所有内容都变得多余,不是吗(尽管检索信息非常容易和快速)?还有2个问题:1.你能多扩展一点反向查找列表的意思吗? 2. 对于多大的矩阵,您认为这样的矩阵太大(我的矩阵总是 n X n 大小)?
    • @Morat 是的,它会的。你有几个选择。您可以使阵列呈锯齿状,因此您不存储该信息。您可以只处理冗余数据,或者您可以使用 2D 数组但将冗余数组值保留为空。虽然冗余存储信息使用 2x 内存,但它更方便一些,因为您不需要确保首先搜索最小/最大(取决于您填充的数组的哪一半)索引。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-31
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多