一、TSP问题

TSP问题(Travelling Salesman Problem)即旅行商问题,又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。

TSP问题是一个组合优化问题。该问题可以被证明具有NPC计算复杂性。TSP问题可以分为两类,一类是对称TSP问题(Symmetric TSP),另一类是非对称问题(Asymmetric TSP)。所有的TSP问题都可以用一个图(Graph)来描述:

V={c1, c2, …, ci, …, cn},i = 1,2, …, n,是所有城市的集合.ci表示第i个城市,n为城市的数目;

E={(r, s): r,s∈ V}是所有城市之间连接的集合;

C = {crs: r,s∈ V}是所有城市之间连接的成本度量(一般为城市之间的距离);

如果crs = csr, 那么该TSP问题为对称的,否则为非对称的。

一个TSP问题可以表达为:

求解遍历图G = (V, E, C),所有的节点一次并且回到起始节点,使得连接这些节点的路径成本最低。

二、粒子群算法

1、基本思想

粒子群算法简称PSO,它的基本思想是模拟鸟群的捕食行为。设想这样一个场景:一群鸟在随机搜索食物。在这个区域里只有一块食物。所有的鸟都不知道食物在那里。但是他们知道当前的位置离食物还有多远。那么找到食物的最优策略是什么呢。最简单有效的就是搜寻目前离食物最近的鸟的周围区域。

PSO从这种模型中得到启示并用于解决优化问题。PSO中,每个优化问题的解都是搜索空间中的一只鸟。我们称之为“粒子”。所有的粒子都有一个由被优化的函数决定的适应值(fitness value),每个粒子还有一个速度决定他们飞翔的方向和距离。然后粒子们就追随当前的最优粒子在解空间中搜索。

PSO 初始化为一群随机粒子(随机解)。然后通过迭代找到最优解。在每一次迭代中,粒子通过跟踪两个"极值"来更新自己。第一个就是粒子本身所找到的最优解,这个解叫做个体极值pBest。另一个极值是整个种群目前找到的最优解,这个极值是全局极值gBest。另外也可以不用整个种群而只是用其中一部分作为粒子的邻居,那么在所有邻居中的极值就是局部极值。

2、粒子公式

在找到这两个最优值时,粒子根据如下的公式来更新自己的速度和新的位置:

v[i] = w * v[i] + c1 * rand() * (pbest[i] - present[i]) + c2 * rand() * (gbest - present[i])

present[i] = present[i] + v[i]

其中v[i]代表第i个粒子的速度,w代表惯性权值,c1和c2表示学习参数,rand()表示在0-1之间的随机数,pbest[i]代表第i个粒子搜索到的最优值,gbest代表整个集群搜索到的最优值,present[i]代表第i个粒子的当前位置。

3、个人见解

截止目前为止,粒子群优化算法大体上可以分为两大类,一类是最初的基本粒子群优化算法,一类是改进后的广义粒子群优化算法,其实PSO最初的设计主要用于处理连续优化问题,如求函数极值,在复杂的组合优化问题上它的应用相当有限,后来经过众多学者的改进才将其应用于求解TSP和单机调度之类的问题。广义粒子群算法模型和遗传算法相当类似,目前网上有关于粒子群算法求解TSP的很多论文或代码都是基于广义粒子群算法的,说简单点就是进化思想,用交叉变异代替了基本粒子群算法的迭代公式,当然他们也还是有粒子群优化的本质思想的,如与全局最优编码交叉,与局部最优编码交叉,变异等都是源自于基本粒子群算法的迭代公式。

三、粒子群优化算法求解TSP问题

关于基本粒子群优化算法的使用,可参考最近这篇文章,

自话粒子群算法 ,既然是求解TSP,使用基本的粒子群算法迭代公式肯定是不行的,在这里我也不想写一个与遗传算法差不多的粒子群算法,确实没必要,只要看了解遗传算法,分分钟就能写出来,在这里我想使用一种,比较特别的迭代方式,先来看看它的迭代公式:

我们使用TSP问题依然来自于tsplib上的att48,这是一个对称TSP问题,城市规模为48,其最优值为10628.其距离计算方法下图所示:

好,下面是具体代码:

package noah;

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.util.ArrayList;

import java.util.Random;

public class PSO {

private int bestNum;

private float w;

private int MAX_GEN;// 迭代次数

private int scale;// 种群规模

private int cityNum; // 城市数量,编码长度

private int t;// 当前代数

private int[][] distance; // 距离矩阵

private int[][] oPopulation;// 粒子群

private ArrayList> listV;// 每科粒子的初始交换序列

private int[][] Pd;// 一颗粒子历代中出现最好的解,

private int[] vPd;// 解的评价值

private int[] Pgd;// 整个粒子群经历过的的最好的解,每个粒子都能记住自己搜索到的最好解

private int vPgd;// 最好的解的评价值

private int bestT;// 最佳出现代数

private int[] fitness;// 种群适应度,表示种群中各个个体的适应度

private Random random;

public PSO() {

}

/**

* constructor of GA

*

* @param n

* 城市数量

* @param g

* 运行代数

* @param w

* 权重

**/

public PSO(int n, int g, int s, float w) {

this.cityNum = n;

this.MAX_GEN = g;

this.scale = s;

this.w = w;

}

// 给编译器一条指令,告诉它对被批注的代码元素内部的某些警告保持静默

@SuppressWarnings("resource")

/**

* 初始化PSO算法类

* @param filename 数据文件名,该文件存储所有城市节点坐标数据

* @throws IOException

*/

private void init(String filename) throws IOException {

// 读取数据

int[] x;

int[] y;

String strbuff;

BufferedReader data = new BufferedReader(new InputStreamReader(

new FileInputStream(filename)));

distance = new int[cityNum][cityNum];

x = new int[cityNum];

y = new int[cityNum];

for (int i = 0; i < cityNum; i++) {

// 读取一行数据,数据格式1 6734 1453

strbuff = data.readLine();

// 字符分割

String[] strcol = strbuff.split(" ");

x[i] = Integer.valueOf(strcol[1]);// x坐标

y[i] = Integer.valueOf(strcol[2]);// y坐标

}

// 计算距离矩阵

// ,针对具体问题,距离计算方法也不一样,此处用的是att48作为案例,它有48个城市,距离计算方法为伪欧氏距离,最优值为10628

for (int i = 0; i < cityNum - 1; i++) {

distance[i][i] = 0; // 对角线为0

for (int j = i + 1; j < cityNum; j++) {

double rij = Math

.sqrt(((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j])

* (y[i] - y[j])) / 10.0);

// 四舍五入,取整

int tij = (int) Math.round(rij);

if (tij < rij) {

distance[i][j] = tij + 1;

distance[j][i] = distance[i][j];

} else {

distance[i][j] = tij;

distance[j][i] = distance[i][j];

}

}

}

distance[cityNum - 1][cityNum - 1] = 0;

oPopulation = new int[scale][cityNum];

fitness = new int[scale];

Pd = new int[scale][cityNum];

vPd = new int[scale];

/*

* for(int i=0;i

*/

Pgd = new int[cityNum];

vPgd = Integer.MAX_VALUE;

// nPopulation = new int[scale][cityNum];

bestT = 0;

t = 0;

random = new Random(System.currentTimeMillis());

/*

* for(int i=0;i

* System.out.print(distance[i][j]+","); } System.out.println(); }

*/

}

// 初始化种群,多种随机生成办法

void initGroup() {

int i, j, k;

for (k = 0; k < scale; k++)// 种群数

{

oPopulation[k][0] = random.nextInt(65535) % cityNum;

for (i = 1; i < cityNum;)// 粒子个数

{

oPopulation[k][i] = random.nextInt(65535) % cityNum;

for (j = 0; j < i; j++) {

if (oPopulation[k][i] == oPopulation[k][j]) {

break;

}

}

if (j == i) {

i++;

}

}

}

/*

* for(i=0;i

* System.out.print(oldPopulation[i][j]+","); } System.out.println(); }

*/

}

void initListV() {

int ra;

int raA;

int raB;

listV = new ArrayList>();

for (int i = 0; i < scale; i++) {

ArrayList list = new ArrayList();

ra = random.nextInt(65535) % cityNum;

for (int j = 0; j < ra; j++) {

raA = random.nextInt(65535) % cityNum;

raB = random.nextInt(65535) % cityNum;

while (raA == raB) {

raB = random.nextInt(65535) % cityNum;

}

// raA与raB不一样

SO s = new SO(raA, raB);

list.add(s);

}

listV.add(list);

}

}

public int evaluate(int[] chr) {

// 0123

int len = 0;

// 编码,起始城市,城市1,城市2...城市n

for (int i = 1; i < cityNum; i++) {

len += distance[chr[i - 1]][chr[i]];

}

// 城市n,起始城市

len += distance[chr[cityNum - 1]][chr[0]];

return len;

}

// 求一个基本交换序列作用于编码arr后的编码

public void add(int[] arr, ArrayList list) {

int temp = -1;

SO s;

for (int i = 0; i < list.size(); i++) {

s = list.get(i);

temp = arr[s.getX()];

arr[s.getX()] = arr[s.getY()];

arr[s.getY()] = temp;

}

}

// 求两个编码的基本交换序列,如A-B=SS

public ArrayList minus(int[] a, int[] b) {

int[] temp = b.clone();

/*

* int[] temp=new int[L]; for(int i=0;i

*/

int index;

// 交换子

SO s;

// 交换序列

ArrayList list = new ArrayList();

for (int i = 0; i < cityNum; i++) {

if (a[i] != temp[i]) {

// 在temp中找出与a[i]相同数值的下标index

index = findNum(temp, a[i]);

// 在temp中交换下标i与下标index的值

changeIndex(temp, i, index);

// 记住交换子

s = new SO(i, index);

// 保存交换子

list.add(s);

}

}

return list;

}

// 在arr数组中查找num,返回num的下标

public int findNum(int[] arr, int num) {

int index = -1;

for (int i = 0; i < cityNum; i++) {

if (arr[i] == num) {

index = i;

break;

}

}

return index;

}

// 将数组arr下标index1与下标index2的值交换

public void changeIndex(int[] arr, int index1, int index2) {

int temp = arr[index1];

arr[index1] = arr[index2];

arr[index2] = temp;

}

// 二维数组拷贝

public void copyarray(int[][] from, int[][] to) {

for (int i = 0; i < scale; i++) {

for (int j = 0; j < cityNum; j++) {

to[i][j] = from[i][j];

}

}

}

// 一维数组拷贝

public void copyarrayNum(int[] from, int[] to) {

for (int i = 0; i < cityNum; i++) {

to[i] = from[i];

}

}

public void evolution() {

int i, j, k;

int len = 0;

float ra = 0f;

ArrayList Vi;

// 迭代一次

for (t = 0; t < MAX_GEN; t++) {

// 对于每颗粒子

for (i = 0; i < scale; i++) {

if(i==bestNum) continue;

ArrayList Vii = new ArrayList();

//System.out.println("------------------------------");

// 更新速度

// Vii=wVi+ra(Pid-Xid)+rb(Pgd-Xid)

Vi = listV.get(i);

// wVi+表示获取Vi中size*w取整个交换序列

len = (int) (Vi.size() * w);

//越界判断

//if(len>cityNum) len=cityNum;

//System.out.println("w:"+w+" len:"+len+" Vi.size():"+Vi.size());

for (j = 0; j < len; j++) {

Vii.add(Vi.get(j));

}

// Pid-Xid

ArrayList a = minus(Pd[i], oPopulation[i]);

ra = random.nextFloat();

// ra(Pid-Xid)+

len = (int) (a.size() * ra);

//越界判断

//if(len>cityNum) len=cityNum;

//System.out.println("ra:"+ra+" len:"+len+" a.size():"+a.size());

for (j = 0; j < len; j++) {

Vii.add(a.get(j));

}

// Pid-Xid

ArrayList b = minus(Pgd, oPopulation[i]);

ra = random.nextFloat();

// ra(Pid-Xid)+

len = (int) (b.size() * ra);

//越界判断

//if(len>cityNum) len=cityNum;

//System.out.println("ra:"+ra+" len:"+len+" b.size():"+b.size());

for (j = 0; j < len; j++) {

SO tt= b.get(j);

Vii.add(tt);

}

//System.out.println("------------------------------Vii.size():"+Vii.size());

// 保存新Vii

listV.add(i, Vii);

// 更新位置

// Xid’=Xid+Vid

add(oPopulation[i], Vii);

}

// 计算新粒子群适应度,Fitness[max],选出最好的解

for (k = 0; k < scale; k++) {

fitness[k] = evaluate(oPopulation[k]);

if (vPd[k] > fitness[k]) {

vPd[k] = fitness[k];

copyarrayNum(oPopulation[k], Pd[k]);

bestNum=k;

}

if (vPgd > vPd[k]) {

System.out.println("最佳长度"+vPgd+" 代数:"+bestT);

bestT = t;

vPgd = vPd[k];

copyarrayNum(Pd[k], Pgd);

}

}

}

}

public void solve() {

int i;

int k;

initGroup();

initListV();

// 每颗粒子记住自己最好的解

copyarray(oPopulation, Pd);

// 计算初始化种群适应度,Fitness[max],选出最好的解

for (k = 0; k < scale; k++) {

fitness[k] = evaluate(oPopulation[k]);

vPd[k] = fitness[k];

if (vPgd > vPd[k]) {

vPgd = vPd[k];

copyarrayNum(Pd[k], Pgd);

bestNum=k;

}

}

// 打印

System.out.println("初始粒子群...");

for (k = 0; k < scale; k++) {

for (i = 0; i < cityNum; i++) {

System.out.print(oPopulation[k][i] + ",");

}

System.out.println();

System.out.println("----" + fitness[k]);

/*

ArrayList li = listV.get(k);

int l = li.size();

for (i = 0; i < l; i++) {

li.get(i).print();

}

System.out.println("----");

*/

}

// 进化

evolution();

// 打印

System.out.println("最后粒子群...");

for (k = 0; k < scale; k++) {

for (i = 0; i < cityNum; i++) {

System.out.print(oPopulation[k][i] + ",");

}

System.out.println();

System.out.println("----" + fitness[k]);

/*

ArrayList li = listV.get(k);

int l = li.size();

for (i = 0; i < l; i++) {

li.get(i).print();

}

System.out.println("----");

*/

}

System.out.println("最佳长度出现代数:");

System.out.println(bestT);

System.out.println("最佳长度");

System.out.println(vPgd);

System.out.println("最佳路径:");

for (i = 0; i < cityNum; i++) {

System.out.print(Pgd[i] + ",");

}

}

/**

* @param args

* @throws IOException

*/

public static void main(String[] args) throws IOException {

System.out.println("Start....");

PSO pso = new PSO(48, 5000, 30, 0.5f);

pso.init("c://data.txt");

pso.solve();

}

}

运行结果截图:

四、总结

对于这个实验结果,其实我个人是不能接受的,但是目前我只能把问题归结于那篇论文提出的迭代公式上,不过那论文年代久远,它上面就试了14个点,这里是48个,差距肯定是有的,或许这里再进行一些调整,没准效果会好些,但是目前我本人时间有限,还来不及深入实验,只能让感兴趣的人来进行深入剥解!

粒子群算法java_基于粒子群算法求解求解TSP问题(JAVA)相关推荐

  1. 【建模算法】基于蚁群算法求解TSP问题(Python实现)

    [建模算法]基于蚁群算法(ACA)求解TSP问题(Python实现) TSP (traveling salesman problem,旅行商问题)是典型的NP完全问题,即其最坏情况下的时间复杂度随着问 ...

  2. 协同过滤推荐算法和基于内容推荐算法的区别?

    文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼:我热爱编程.热爱算法.热爱开源.所有源码在我的个人github :这博客是记录我学习的点点滴滴,如果您对 Python.Java.AI ...

  3. 多目标粒子群优化算法_基于粒子群优化的投资组合优化研究

    原文链接: 基于粒子群优化的投资组合优化研究​tecdat.cn 我今年的研究课题是使用粒子群优化(PSO)的货币进位交易组合优化.在本文中,我将介绍投资组合优化并解释其重要性.其次,我将演示粒子群优 ...

  4. 粒子群算法求解旅行商问题TSP (JAVA实现)

    粒子群算法求解旅行商问题TSP 写在开头: 最近师妹的结课作业问我,关于使用粒子群求解TSP问题的思路.我想了想,自己去年的作业用的是遗传算法,貌似有些关联,索性给看了看代码.重新学习了一遍粒子群算法 ...

  5. python粒子群喷发_Python基于粒子群优化的投资组合优化研究

    原文链接:http://tecdat.cn/?p=6811 我今年的研究课题是使用粒子群优化(PSO)的货币进位交易组合优化.在本文中,我将介绍投资组合优化并解释其重要性.其次,我将演示粒子群优化如何 ...

  6. 【智能优化算法-野狗优化算法】基于野狗优化算法求解单目标优化问题附matlab代码

    1 内容介绍 非洲野狗主要生活在非洲的干燥草原和半荒漠地带,活跃于草原.稀树草原和幵阔的干燥灌木丛.它们通常群居,领土范围大小在200到2000平方公里之间,通过叫声进行定位.采取群体合作方式猎杀中型 ...

  7. 【智能优化算法-热交换算法】基于热交换优化算法求解多目标优化问题附matlab代码

    ​1 内容介绍 热 交 换 优 化 (Thermal Exchange Optimization, TEO)算法是一种基于牛顿冷却定律的新型优化算 法,在该算法中,物体的热损失率与物体和其周围 环境的 ...

  8. mahout 推荐算法 java_推荐系统之推荐算法实战:mahout推荐算法框架

    1.Mahout介绍 1.1概述 根据百度的解说,Mahout 是 Apache Software Foundation(ASF) 旗下的一个开源项目,提供一些可扩展的机器学习领域经典算法的实现,旨在 ...

  9. 仿射投影算法 matlab,基于仿射投影算法的时延估计

    Signal Process & System 号与系 基于仿射投影算法的时延估计 摘要:在时间延迟计中,通常利用互相关箅法对8寸延进行估计.然而,互相关算法受操声影较人,在低信比时无法准确对 ...

最新文章

  1. 信息系统项目管理知识--项目整合管理
  2. nyist 一笔画问题
  3. 内存泄漏与内存溢出的区别
  4. golang 怎么把指针内容也打印出来_FDM工艺3D打印出来的模型表面粗糙怎么解决?...
  5. 初识ABP vNext(4):vue用户登录菜单权限
  6. 【CodeForces - 510D】Fox And Jumping(dp,stlmap,数论的性质)
  7. 安卓学习笔记19:常用控件 - 单选按钮和复选框
  8. 递归下降分析法的基本思想。_语法分析 | 递归下降分析算法
  9. 那些不用上班的老人每天是不是很幸福?
  10. 忆芯科技发布新一代国产主控芯片STAR1000P!4月完成量产版本
  11. 机器学习基础(四十)—— 将距离转换为权重
  12. inurl:faq.php?action=,什么是财富等级 | 帮助 | 酷狗直播 | 就是歌手多
  13. java中cleanup的使用_java – google guava缓存invalidateAll()和cleanUp()之间的区别
  14. 印象团队EverTeam for Mac(团队协作工具)
  15. 苹果 2019 卖什么?新 iPhone 值不值得买?
  16. 如何做好SEM竞价营销
  17. 今日全国油价查询2022-03-08
  18. brew的MAC安装
  19. jieba库的安装与使用
  20. 爱情智慧:结婚是什么感觉

热门文章

  1. 言论-摘自《读者》2006年第11期
  2. oracle table()函数用法
  3. Win7+64位+Msflxgrd.ocx注册
  4. 华为正式发布nova4系列手机 首创极点全面屏引关注
  5. 自然语言处理--朴素贝叶斯-情感分析
  6. Microchip PIC系列8位单片机入门教程(四)中断
  7. Ubuntu 安装 Mysql【详细步骤】
  8. ubuntu 安装mysql
  9. 这款免费的多屏亮度调节软件,真的爱了
  10. chromium OS编译过程