基于 PSO 算法解决 TSP 项目
2018-01-27 02:36
204 查看
PSO (Particle Swarm Optimization) 算法即粒子群优化算法,源于对鸟群捕食行为的学习。基本思想是:个体获取的局部信息提供给群体,群体根据所有局部信息获得一个动态的全局最优解,每个个体再根据这个全局最优解调整自身的局部最优解,这个过程进行迭代,直到达到终止条件。
TSP (Traveling Salesman Problem) 即旅行商问题,简单来说就是:给定 n 个城市的位置,求一条访问各个城市一次的最短路径,TSP 也是一个组合优化问题。
PSO 算法基础公式
这里,Vj 代表每个粒子的速度;w 是惯性权重系数,有利于算法的收敛;c1 和 c2 分别为局部加速权重系数和全局加速权重系数,决定了下一代的局部速度取决于局部最优解多一些,还是全局最优解多一些;r1 和 r2 是两个 0~1 中间的随机数,也是为了算法收敛。
下面是我在 report 里做的 PSO 算法运行流程图:
PSO
算法流程图
但很明显,PSO 算法更适合用来解决连续优化问题,而旅行商问题是一个组合优化问题。经过大量的论文学习和讨论后,使用了一种改进的 PSO 算法,引入了交换子和交换序的概念。
假设在一个旅行商问题中,有 n 个城市节点,那么这个问题的解序列可记为 S = (ai), i = 1, 2, …, n. 那么 SO(i1, i2) 就是一个交换子,i1 和 i2 表示城市节点 a1 和 a2. 若对解序列进行 S’ = S + SO(i1, i2) 的运算,就是将解序列 S 中 a1 和 a2 的位置进行调换。多个交换子的序列 SS = (SO1, SO2, …, SOn) 就是一个交换序,其中交换子的顺序是有意义的,不同的顺序可能产生不同的解序列。
放在这个具体路线规划问题中,就是先将所有城市节点随机排列,得到一个解序列,然后对城市节点进行逐个调换,将调换前后的路径长度进行对比,如果变好则更新全局最优解,否则继续寻找更佳的交换子和交换序,在这一过程中,w 系数就起到了收敛的作用,它会使我们进行调换的局部解序列越来越短。
核心程序
改变 swarm 的数目和迭代次数,得到的路径长度如下:
随着两个参数的无限增长,得到的最佳路径也会越来越短,但同时所耗的内存和时间也会有所增加。
最佳路径大概长这样:
P.S. 在 IntelliJ 里面做界面真的太方便了。
代码已上传到 github,点击传送门~
TSP (Traveling Salesman Problem) 即旅行商问题,简单来说就是:给定 n 个城市的位置,求一条访问各个城市一次的最短路径,TSP 也是一个组合优化问题。
PSO 算法基础公式
这里,Vj 代表每个粒子的速度;w 是惯性权重系数,有利于算法的收敛;c1 和 c2 分别为局部加速权重系数和全局加速权重系数,决定了下一代的局部速度取决于局部最优解多一些,还是全局最优解多一些;r1 和 r2 是两个 0~1 中间的随机数,也是为了算法收敛。
下面是我在 report 里做的 PSO 算法运行流程图:
PSO
算法流程图
但很明显,PSO 算法更适合用来解决连续优化问题,而旅行商问题是一个组合优化问题。经过大量的论文学习和讨论后,使用了一种改进的 PSO 算法,引入了交换子和交换序的概念。
假设在一个旅行商问题中,有 n 个城市节点,那么这个问题的解序列可记为 S = (ai), i = 1, 2, …, n. 那么 SO(i1, i2) 就是一个交换子,i1 和 i2 表示城市节点 a1 和 a2. 若对解序列进行 S’ = S + SO(i1, i2) 的运算,就是将解序列 S 中 a1 和 a2 的位置进行调换。多个交换子的序列 SS = (SO1, SO2, …, SOn) 就是一个交换序,其中交换子的顺序是有意义的,不同的顺序可能产生不同的解序列。
放在这个具体路线规划问题中,就是先将所有城市节点随机排列,得到一个解序列,然后对城市节点进行逐个调换,将调换前后的路径长度进行对比,如果变好则更新全局最优解,否则继续寻找更佳的交换子和交换序,在这一过程中,w 系数就起到了收敛的作用,它会使我们进行调换的局部解序列越来越短。
核心程序
private void particle(int i) { ArrayList<SO> Vi; int len; int j; float ra; float rb; ArrayList<SO> Vii = new ArrayList<SO>(); // refresh velocity // Vii=wVi+ra(Pid-Xid)+rb(Pgd-Xid) Vi = listV.get(i); // wVi+表示获取Vi中size*w取整个交换序列 len = (int) (Vi.size() * w); for (j = 0; j < len; j++) { Vii.add(Vi.get(j)); } // Pid-Xid ArrayList<SO> a = minus(Pd[i], oPopulation[i]); ra = random.nextFloat(); // ra(Pid-Xid) len = (int) (a.size() * ra); for (j = 0; j < len; j++) { Vii.add(a.get(j)); } // Pgd-Xid ArrayList<SO> b = minus(Pgd, oPopulation[i]); rb = random.nextFloat(); // rb(Pgd-Xid) len = (int) (b.size() * rb); for (j = 0; j < len; j++) { SO tt = b.get(j); Vii.add(tt); } // save new Vii listV.set(i, Vii); // refresh position // Xid’=Xid+Vid add(oPopulation[i], Vii); }
改变 swarm 的数目和迭代次数,得到的路径长度如下:
随着两个参数的无限增长,得到的最佳路径也会越来越短,但同时所耗的内存和时间也会有所增加。
最佳路径大概长这样:
P.S. 在 IntelliJ 里面做界面真的太方便了。
代码已上传到 github,点击传送门~