Metaheuristic shuffle

时间:2014-09-08 23:20:53

标签: c++ genetic-algorithm shuffle heuristics

我目前正在研究NP完全问题,并为此目的实施了个人遗传算法。结果超出了我的预期。通过精心设计的健身功能和仔细调整的几个人口/突变,我猜GA在某些情况下可以成为一个出色的工具。

无论如何,我现在正在寻找能够产生最佳混洗输出的元启发式(GA,模拟退火......)。

通过shuffle,我的意思是,在这种情况下,一个有限集的无偏(àla Fisher-Yates)随机置换。像卡片组。一个巨大的(约500!排列)。

这套的价值都不同。不会发生任何碰撞。

由于这种限制,我在实施GA解决方案时遇到了一些困难。实际上,改组的值不能用作基因。很容易理解为什么:

#include <iostream>
#include <vector>
#define SPLICING 50 // 50|50 one-point crossover
int crossover(int gene, int DNA_length, int A, int B)
{if (gene < (SPLICING*DNA_length)/100) return A; else return B;}

int main() {
    std::vector<int> A, B, C;
    A = { 3, 4, 8, 12, 2, 0, 9, 7, 10, 20 };
    B = { 8, 10, 3, 4, 20, 0, 7, 9, 2, 12 };
    int DNA_length = int(A.size());
    for (int i=0; i<DNA_length; i++) {
        C.push_back(crossover(i, DNA_length, A[i], B[i]));
                    if (i == DNA_length/2) std::cout << "| ";
                    std::cout << C[i] << " ";}
            }

输出:3 4 8 12 2 | 0 7 9 2 12

有两次碰撞(2,12)。

我的预期输出是这样的:3 4 8 12 2 | 0 7 9 10 20(没有碰撞,原始套装的完美洗牌)。

然后,我需要对这些值的顺序进行编码,以避免这种困难。

一种天真的方式是使用唯一键标识每个值。但是随后创建的集合是序数,因为它指的是值的排序。

我认为交叉功能必须处理父母DNA的普通性。但我无法解决在没有碰撞的情况下混合序数集(整个DNA)的两个非线性有序序数子集(父母的DNA切片)的问题!

也许我只能依靠突变来收敛。没有选择,没有父母/子女,只有同一组中的交换功能(个人的DNA)。简而言之:不是很有说服力。

确实很容易在一个独特的有限集中置换序数(例如,平凡:第一个成为第七个;第二个,第十个等等)。但我不确定当集合B 的第二个成为新集合的十分之一时,集合A 的第一个成为第七个是否有意义。

然后,我的问题是:

在您看来,在遗传算法的上下文中,是否可以使用交叉函数对一组的正常性进行改组?如果不是,你能否建议一种比蛮力,爬山技术或遗传算法更有效的元启发式方法?

谢谢。

1 个答案:

答案 0 :(得分:2)

您正在寻找的是基于订单的遗传算法。你有许多基于订单的交叉和变异操作符,可以解决这类问题。最简单的交叉算子的工作原理如下:

  1. 选择交叉点
  2. 将交叉点内的parent1从零件复制到第一个子。
  3. 列出parent1在交叉点之外的元素
  4. 将未使用列表的元素按照parent2
  5. 中使用的顺序排列
  6. 按照步骤4中建立的顺序将这些元素复制到第一个子。
  7. 你可以在下图中看到我书中的一个例子(对不起,但描述是葡萄牙语 - 请与上面的列表相关):

    enter image description here

    您可以在网上搜索基于订单的运营商,或者如果您愿意,请查看我在My Geneetic Algorithm book的书中的数据。您感兴趣的数字来自第10章(您可以使用Google翻译来理解传说)。

    您不必介意本书使用序号 - 如果您没有重复,所有解释的概念对您的问题都有效。

    我希望它有所帮助。