遗传算法解决最短路径问题

实例描述:

配送中心数为 \(1\),客户数 $k $为 \(8\),车辆总数 $m $为 \(2\);车辆载重皆为 \(8\) 吨;各客户点需求为 \(g(i = 1, 2, ... , 8)\)(单位为吨),已知客户点与配送中心的距离如表 $1 $(其中 \(0\) 表示中心仓库),要求合理安排车辆的运输路线,使总运输里程最小。

客户点与配送中心的距离表:

cij 0 1 2 3 4 5 6 7 8
0 0 4 6 7.5 9 20 10 16 8
1 4 0 6.5 4 10 5 7.5 11 10
2 6 6.5 0 7.5 10 10 7.5 7.5 7.5
3 7.5 4 7.5 0 10 5 9 9 15
4 9 10 10 10 0 10 7.5 7.5 10
5 20 5 10 5 10 0 7 9 7.5
6 10 7.5 7.5 9 7.5 7 0 7 10
7 16 11 7.5 6 7.5 9 7 0 10
8 8 10 7.5 15 10 7.5 10 10 0

各客户点需求:

g1 g2 g3 g4 g5 g6 g7 g8
1 2 1 2 1 4 2 2

运行结果:

【Attention】下图并非最优结果,只是为了测试程序的正确性。可以尝试加大次数改良结果。

遗传算法分析

顾名思义,遗传算法是根据遗传规律写的一个算法,但是相比于医学中的遗传来讲,这里讲的遗传算法十分的简单。

遗传算法的核心有三个部分:交叉、变异、轮盘赌。

解决问题的关键和难点就是理解遗传算法的作用:通过改变交叉和变异改变基因特性,导致个体发生改变,从而影响到适应度,最后利用轮盘赌的方式淘汰掉一些个体。

看一下整个程序的运行流程:

\[ 4 5 2 7 3 6 1 8 \\ 2 8 1 5 7 6 3 4 \\ 4 6 7 2 5 1 3 8 \\ 4 2 6 5 1 7 8 3 \\ 1 7 3 2 4 8 5 6 \\ 3 2 8 6 4 7 1 5 \]

上面的数据一用有\(6\)\(8\)列,我们可以说有\(6\)个个体,每个个体的基因长度是\(8\)。其中\(6\)可以说是种群大小,\(8\)可以说是每个个体的特征数目。到目前为止,我们可以定义一种运算规则了:通过每个个体的特征计算出该个体的样子(\(X\)),然后根据个体的样子,求出该个体的适应度(\(Y\))。

整个流程是:个体特征 --->> 个体 --->> 适应度

交叉过程:[Source Code]

假设个体\(1\)和个体\(2\)发生了交叉,交叉点在第\(7\)列,那么交叉之前,两个个体为:

\[ 4 5 2 7 3 6 1 8 \\ 2 8 1 5 7 6 3 4 \]

交叉之后,两个个体为:

\[ 4 5 2 7 3 6 3 4 \\ 2 8 1 5 7 6 1 8 \]

可以发现,交叉就是把交叉点后的所有列数据都进行交换(包括交叉点所在的列)。

变异过程:[Source Code]

假设个体4发生了变异,发生变异的点在第\(3\)点,那么变异之前为:

\[ 4 2 6 5 1 7 8 3 \]

变异之后,该个体变为:

\[ 4 2 3 5 1 7 8 3 \]

可以发现,变异就是把变异点所在的位置随机的更换一个数字。

轮盘赌:[Source Code]

轮盘赌的规则很简单:在左轮手枪的六个弹槽中放入一颗或多颗子弹,任意旋转转轮之后,关上转轮。游戏的参加者轮流把手枪对着自己的头,扣动板机;中枪的当然是自动退出,怯场的也为输,坚持到最后的就是胜者。

遗传算法中的轮盘赌和俄罗斯轮盘赌还是有点差距的。这里不以子弹作为筹码,而是以概率作为筹码。

还是以上面的\(6\)个个体作为例子,我们对上面的\(6\)个个体都求出适应度(\(Y\))后,\(6\)个适应度可能是下面的样子:

\[ 99.0000 \\ 105.5000 \\ 100.5000\\ 102.0000 \\ 103.0000 \\ 95.5000 \]

然后求出总适应度(sum(Y))将每个个体的适应度除以总适应度,得到下面的结果:

\[ 0.1635 \\ 0.1742\\ 0.1660\\ 0.1685\\ 0.1701\\ 0.1577 \]

然后,对6个个体适应度从上到下累加求和,得到下面的结果:

\[ 0.1635\\ 0.3377\\ 0.5037\\ 0.6722\\ 0.8423\\ 1.0000 \]

对种群的处理已经完成,那么应该淘汰哪部分,是现在应该应该考虑的问题。

我们可以生成一个随机数序列,然后从小到大排序,如下:

\[ 0.0005\\ 0.1899\\ 0.3298\\ 0.8077\\ 0.8875\\ 0.9450 \]

比较规则:

原则上,如果不对比较次数做限制的话,那么整个比较过程会是如下的效果:

但是,鉴于种群数量有限,只能保存\(6\)个个体,因此,我们只保留箭头起始点较大的个体(该个体指向的概率相对本身小)。经过筛选后,我们得到下面的个体可以被保留:

也就是个体\(1\)\(2\)\(5\)\(6\)被筛选了下来,而且,个体\(2\)\(6\)被保留了两次。

以上就是整个遗传算法的核心了。其余部分(如何根据个体计算适应度,也就是如何根据\(x\)求出\(y\))需要根据具体情况做修改。本体用到的代码可以查看代码仓库

【注意】在交叉和变异中,需要将重复的元素去重,才能在适应于本题目的求解。去重操作可以参考[Source Code]。

猜你喜欢

转载自www.cnblogs.com/toooney/p/10977060.html