C++ 元启发式洗牌

C++ 元启发式洗牌,c++,genetic-algorithm,shuffle,heuristics,C++,Genetic Algorithm,Shuffle,Heuristics,我目前正在研究一个NP完全问题,并为此实现了一个个人遗传算法。结果超出了我的预期。有了精心设计的适应度函数和一对仔细调整的种群/变异,我想遗传算法在某些情况下可能是一个很好的工具 无论如何,我现在正在寻找一种元启发式遗传算法,模拟退火。。。能够产生最佳洗牌输出 我的意思是,在这种情况下,一个无偏的Fisher-Yates有限集的随机排列。就像一副扑克牌。一个大的~500!排列 这一组的值都不同。预计不会发生碰撞 由于这个限制,我在实现GA解决方案时遇到了一些困难。事实上,混乱的值不能用作基因。很

我目前正在研究一个NP完全问题,并为此实现了一个个人遗传算法。结果超出了我的预期。有了精心设计的适应度函数和一对仔细调整的种群/变异,我想遗传算法在某些情况下可能是一个很好的工具

无论如何,我现在正在寻找一种元启发式遗传算法,模拟退火。。。能够产生最佳洗牌输出

我的意思是,在这种情况下,一个无偏的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] << " ";}
            }
产出:348122 | 079212

有两次碰撞2,12

我的预期输出是这样的:3 4 8 12 2 | 0 7 9 10 20无碰撞,完美地洗牌原始设置

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

一种简单的方法是用唯一的键标识每个值。但随后创建的集合是有序的,因为它指的是值的顺序

看来交叉函数必须处理双亲DNA的有序性。但是我不能把我的头绕到混合两个非线性有序的有序子集父母的DNA切片的有序集整个DNA没有冲突的问题上

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

在一个唯一的有限集合中排列序数确实很容易,例如:第一个变为第七个;第二、第十等。。但我不确定说A组的第一个变为第七个,而B组的第二个变为新组的第十个是否有意义

那么,我的问题是:

在你看来,在遗传算法的背景下,可以使用交叉函数对集合的有序性进行洗牌吗?如果没有,你能推荐一种比蛮力、爬山技术或遗传算法更有效的元启发式方法吗


谢谢。

您正在寻找的是基于顺序的遗传算法。你有很多基于顺序的交叉和变异算子来处理这类问题。最简单的交叉运算符的工作原理如下:

选择交叉点 将交叉点内的零件从父对象1复制到第一个子对象。 列出位于交叉点之外的parent1元素 将未使用列表中的元素按与parent2中使用的相同顺序排列 按照步骤4中确定的顺序将这些元素复制到第一个子元素。 您可以在下图中看到我的书中的一个示例,抱歉,但是描述是葡萄牙语的-请与上面的列表关联:

您可以在网上搜索基于订单的运营商,或者如果您愿意,请查看我的书中的数字。你感兴趣的数字来自第10章,你可以使用谷歌翻译来理解这些传说

你不必介意这本书使用的是序列号——如果你没有重复,所有解释的概念对你的问题都是有效的


我希望这会有所帮助。

染色体的交配通常会导致后代发生碰撞,从而产生许多不合适的解决方案。你是否考虑过在突变之前或之后操纵后代以确保溶液中没有碰撞?也许碰撞基因可以随机分配或基于原始位置的父母连续分配。这不是理想的气体,但它可能有助于消除所有不合适的解决方案。另外,使用变异不是说牌组中的一些牌在洗牌时可以被其他牌替换吗?这确实是一种可能性,但我担心它会极大地增加随机性因素。假设你保持了来自父母1[1,4,3,2 |的完整DNA部分。然后你必须修改来自父母2 | 2,7,5,0]的DNA部分,以使孩子的DNA中的所有值都是唯一的[1,4,3,2 | 6*,7,5,0]。因此,这个DNA的第二部分并不能真正反映父母2的DNA的质量。如果我们认为这是一个突变,这个突变太重要了,在我的病例中可能超过了整个DNA的5%。所以随机性比遗传选择更大。谢谢你的回答!非常感谢你。我刚刚实现了这个解决方案一点交叉,它给出了令人鼓舞的结果!我希望它对同样情况下的人们有用。值得一提的是:有不同的基于排列/顺序的交叉算子,它们旨在继承不同的信息
激动。假设你有一个像14 5 0 2 3 6 7这样的人,那就很好了。它有什么好处?例如,是1紧挨着4,无论它们出现在字符串中的什么位置,还是4正好位于第二个位置?你可以研究不同的算子,它们保留了好父母的不同属性,这会严重影响性能。这就是为什么IMO基于顺序的遗传算法很难调整的原因。我们可以看到两种集合序数:最优序数子集这个数必须在这个数之后的三个位置,最优全局序数这个数应该在集合的第十个位置。如果我们只关注前者,就像n!越大,解决方案越可能是次优的;仅在后一种情况下,由于父代2的DNA的准随机性,在合理的时间内不可能找到解决方案。也许关键是将这两种方法结合起来,即序数的序数。