干货 | 变邻域搜索算法(Variable Neighborhood Search,VNS)超详细一看就懂
变邻域搜索
介绍
变邻域搜索算法(VNS)是一种改进型的局部搜索算法。它利用不同的动作构成的邻域结构进行交替搜索,在集中性和疏散性之间达到很好的平衡。
变邻域搜索算法依赖于以下事实:
- 一个邻域结构的局部最优解不一定是另一个邻域结构的局部最优解。
- 全局最优解是所有可能邻域的局部最优解。
变邻域搜索算法主要由变邻域下降搜索(VND)和扰动过程两个部分组成
变邻域下降VND
伪代码
- 给定初始解S; 定义m个邻域
- 使用邻域结构Ni进行搜索,如果在找到一个比S更优的解S′,则令S=S′, i=1
- 如果搜遍邻域结构Ni仍找不到比S更优的解,则令i++。
- 如果i≤m ,转步骤2。
- 输出最优解S
示意图
- 当在本邻域搜索找不出一个比当前解更优的解的时候,我们就跳到下一个邻域继续进行搜索。如图中虚黑线所示。
- 当在本邻域搜索找到了一个比当前解更优的解的时候,我们就跳回第一个邻域重新开始搜索。如图中红线所示
扰动过程
通过一定的规则,将一个解变换到另一个解
VNS过程
伪代码
干货 | 变邻域搜索算法解决0-1背包问题(Knapsack Problem)代码实例
- 邻域动作1:将解决方案selection[n]的第i位取反(i=1,2,3,4……n)
- 邻域动作2:对于解决方案selection[n],在第i (i=1,2,3,4……n)位取反的情况下,依次将第j (j=i+1,2,3,4……n)位也取反
- 邻域动作3:交换第i位和第i-3位的数。如果i<3。就交换最后的
- shaking过程:随机取反一些位
干货 | 变邻域搜索算法(VNS)求解TSP(附C++详细代码及注释)
VND邻域示意图
论文拾萃 | 基于树表示法的变邻域搜索算法求解考虑后进先出的取派货旅行商问题(附C++代码和详细代码注释)
考虑后进先出的取派货旅行商问题问题描述
假设车辆从起点(depot)出发去完成所有任务,每个任务分别对应着一个位于不同地理位置的取货点和派货点,需要制定一条路线来保证总费用最小。其中,从起点出发提供服务的车辆只有一辆;车辆必须先到达取货点获得货物才能去派货点;车辆装卸货时必须服从后进先出原则
使用树表示法的变邻域搜索算法求解考虑后进先出的取派货旅行商问题
伪代码
步骤1,设置最大迭代次数max_iter、最大无改进迭代次数max_nonimproving、种群大小pop_size等参数;
步骤2,新建大小为pop_size的种群population(即新建大小为pop_size的数组);
步骤3,初始化当前最好解S_best;
步骤6-8,初始化种群population(即将个体S_best执行pop_size次扰动操作);
步骤10-18,对种群population的每个个体使用局部搜索算子、ATSP算子、交叉算子crossover进行搜索;函数local_search()使用了5种邻域搜索算子,就是前文提到的Variable neighborhood Descent阶段;
步骤19-24,更新当前解S_current和全局最好解S_best;步骤25-27,对种群population使用扰动算子perturbation进行一定的扰动
函数local_search()采用的5种搜索算子
-
子树移位算子:随机删除原树中的一棵子树,遍历插入到树中的任意节点下,邻域为所有子树移位可能得到的解的集合。如下图所示,图(a)、(b)分别为初始解和经过子树移位后的解。
子树移动算子 -
子树交换算子:随机选择原树中的两棵子树并交换他们的位置。邻域为子树交换算子完全遍历能得到的解的集合。如下图所示,图(a)、(b)分别为初始解和经过子树交换后的解。
子树交换算子 -
节点移位算子:随机删除原树中的一个节点,遍历插入到树中的任意节点下。邻域为节点移位算子完全遍历能得到的解的集合。如下图所示,图(a)为初始解,删除节点x后将其作为节点0的子节点可以有4种情况,即如图(c),(d),(e)和(f)。
节点移位算子 - 节点交换算子:随机选择原树中的两个节点并交换它们的位置。
- 混合移位算子:随机删除原树中的若节点,随机插入到树中的任意位置
- ATSP算子:随机选择原树中的一个节点,如果此节点的子节点数目小于8,则使用穷举法优化子节点服务顺序;否则使用RAI算法进行搜索(即从此节点的子节点集合中随机踢出若干节点,再使用贪婪算法进行插入)
- 交叉算子crossover:随机删除原树T1中的一棵子树Ts,然后根据树T2中的父子关系将删除子树Ts中的节点以贪婪的规则插回到原树T1中
- 扰动算子perturbation:随机删除原树T1中的一棵子树,然后利用贪婪算法将删除子树中的节点插回到原树T1中