遗传算法绘制图形?职位分配问题

时间:2011-07-12 12:22:20

标签: algorithm graph genetic-algorithm

我手头有一个任务问题,我想知道应用本地搜索技术达到理想解决方案是多么合适(搜索空间非常大)。

我有一个有向图(流程图),我希望在二维平面上以一种非常清晰,易懂和易于人眼阅读的方式进行可视化。因此;我将为每个顶点分配(x,y)位置。我正在考虑使用模拟退火,遗传算法或您建议的任何此类方法来解决此问题

输入:图表G =(V,E)
输出:一组分配{(xi, yi) for each vi in V}。换句话说,每个顶点将被分配一个位置(x,y),其中坐标都是整数,并且> = 0。

这些是我将用来判断解决方案的标准(我欢迎任何建议):

  • 交叉边的数量应该是最小的,
  • 所有边缘都朝一个方向流动(即从左到右),
  • 高角度分辨率(由两个边缘形成的最小角度 事件发生在同一个顶点上),
  • 小范围 - 最不重要。

此外;我有一个初始配置(位置到顶点的分配),手工制作。这非常混乱,这就是为什么我要尝试自动化这个过程。

我的问题是,

  • 采用本地搜索技术有多明智?多大可能 会产生预期的结果吗?

  • 我应该从什么开始?模拟退火,遗传算法 或其他什么?

  • 我应该在开头随机播种还是使用初始播种 配置开始?

  • 或者,如果您已经知道类似的实现/伪代码/事物,请指出。

任何帮助将不胜感激。感谢。

编辑:它不需要很快 - 不是实时的。此外; | V | = ~200,每个顶点平均有大约1.5个输出边。该图表没有断开连接的组件。它确实涉及周期。

5 个答案:

答案 0 :(得分:4)

我建议查看http://www.graphviz.org/Theory.php,因为graphviz是领先的开源图形可视化工具之一。

根据分配的内容,将graphviz完全用于可视化可能是有意义的。

答案 1 :(得分:1)

This paper是对各种方法的非常好的概述。 Roberto Tomassia's book也是一个不错的选择。

答案 2 :(得分:0)

http://oreilly.com/catalog/9780596529321 - 在本书中,您可能会发现用于2D图形精细可视化的遗传算法的实现。

在类似的情况下,我更喜欢使用遗传算法。你也可以从随机初始化的人口开始 - 根据我的经验,经过几次迭代,你会找到相当不错的(但也不是最好的)解决方案。

另外,使用java你可能会提出这个算法(孤立岛屿策略) - 它是相当有效的改进。

另外,我想建议你差异进化算法。根据我的经验 - 它比遗传优化更快地找到解决方案。

答案 3 :(得分:0)

要回答你的第一个问题,我必须说这取决于。这取决于许多不同的因素,例如:

  • 需要多快(是否需要实时完成?)
  • 有多少个顶点
  • 与顶点数量相比有多少条边(即它是密集的还是稀疏的图形?)

如果需要实时完成,那么本地搜索技术就不是最好的,因为它们可能需要一段时间才能获得良好的结果。如果图表的大小很小,它们只会足够快。如果它开始时很小,则不必使用本地搜索开始。

在你描述的时候,已经存在用于渲染图形的算法。问题是,问题在哪个时候变得太大而无法发挥作用?我不知道这个问题的答案,但我相信你可以做一些研究来找出答案。

现在回答有关本地搜索实施的问题。

根据我的个人经验,模拟退火比遗传算法更容易实现。但是我认为这个问题很好地转化为两种设置。我会从SA开始。

对于模拟退火,您可以从随机配置开始。然后,您可以通过移动一个或多个顶点一些随机距离来随机扰动配置。我相信你可以完成算法的细节。

对于遗传算法方法,您也可以从随机填充开始(每个图形具有顶点的随机坐标)。突变可以像我描述的SA算法中的扰动一样。重组可以简单地从父母那里获取随机顶点并在子图中使用它们。再说一次,我相信你可以填补这些空白。

总结:仅当您的图表足够大以保证它并且如果您不需要超快速完成(比如不到几秒钟)时,请使用本地搜索。否则使用不同的算法。

编辑:根据您的图形参数,我认为您可以使用最容易编码的算法。在V = 200的情况下,即使是O(V ^ 3)算法也是足够的。就个人而言,我觉得模拟退火是最简单和最好的路线。

答案 4 :(得分:0)

function String generateGenetic()
String genetic = "";
for each vertex in your graph
    Generate random x and y;
    String xy = Transform x and y to a fixed-length bit string;
    genetic + = xy;
endfor
return genetic;

写一个函数double evaluate(String genetic),它会给你一定程度的满足感。 (可能基于有多少边相交和边缘方向。

你的计划:

int population = 1000;
int max_iterations = 1000;
double satisfaction = 0;
String[] genetics = new String[population]; //this is ur population;
while((satisfaction<0.8)&&(count<max_iterations)){
    for (int i=0;i<population;i++){
        if(evaluate(genetics[i])>satisfaction)
            satisfaction = evaluate(genetics[i]);
        else
            manipulate(genetics[i]);
    }
}

funciton操作可以翻转一些字符串或多个位或编码顶点的x和y的部分,或者可能完全生成新的遗传字符串或尝试解决其中的问题(指向边缘)。