基于遗传算法的TSP求解问题实验报告.docx
《基于遗传算法的TSP求解问题实验报告.docx》由会员分享,可在线阅读,更多相关《基于遗传算法的TSP求解问题实验报告.docx(18页珍藏版)》请在冰豆网上搜索。
基于遗传算法的TSP求解问题实验报告
TSP问题求解实验报告
一、实验内容
旅行商问题,即TSP问题(TravelingSalesmanProblem)是数学领域中著名问题之一。
假设有一个旅行商人要拜访N个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。
路径的选择目标是要求得的路径路程为所有路径之中的最小值。
本次实验要求利用遗传算法和蚂蚁算法分别对TSP问题求解,并要求求解时间和求解结果均在可接受范围内。
二、实验目的
掌握遗传算法GA基本思想,并能结合实际问题对算法进行相应调整,最终解决问题。
三、实验原理
1.遗传算法
遗传算法是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。
遗传算法是从代表问题可能潜在的解集的一个种群开始的,而一个种群则由经过基因编码的一定数目的个体组成。
每个个体实际上是染色体带有特征的实体。
染色体作为遗传物质的主要载体,即多个基因的集合,其内部表现(即基因型)是某种基因组合,它决定了个体的形状的外部表现,如黑头发的特征是由染色体中控制这一特征的某种基因组合决定的。
因此,在一开始需要实现从表现型到基因型的映射即编码工作。
由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度大小选择个体,并借助于自然遗传学的遗传算子进行组合交叉和变异,产生出代表新的解集的种群。
这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码,可以作为问题近似最优解。
下面是简单遗传算法的求解结构:
需要指出的是,适应度函数、选择、交叉和变异操作均要根据实际问题进行灵活变更,并非固定模式。
针对本次实验的TSP问题,下面给出我在遗传算法中采用的方法。
(1)适应度函数
该函数是算法的关键,通过它对这个繁衍出来的后代进行评估打分。
在TSP问题中,路径越短,分数越高,故而适应度函数可设置为
,不同的计算方法会影响算法的收敛速度,直接影响结果和性能。
(2)选择操作
利用轮盘赌的方式选出优秀的物种,进入下一代。
选择概率的计算公式为
,其中i表示种群中的任一物种;选择过程示意如下图所示。
考虑到优化算法性能,我加入了“精英保留策略”,即并非所有物种均参与赌轮,而是事先选出适应度最高的物种,复制若干进入下一代后,再让剩余的物种参与赌轮,最终形成新种群。
这样避免了因为概率原因,使得优秀物种沧海遗珠的情况发生,但这样做也容易陷入局部最优。
(3)交叉操作
物种基因的编码形式是以“城市编号”为元素的,在实现交叉操作时首先任选一个位置作为起点,交换两个物种的后半段基因。
但需考虑的是,交换后的基因可能与物种已有的基因重复,故而需要再加上冲突处理操作。
交叉操作示意如下图所示。
(4)变异操作
“变异”是跳出局部最优解的一个重要法宝。
我采用的是随机两个位置,逆转其之间的城市编号,即随机产生1和n之间的两相异整数k和m,若k变为
;若k>m,则交换两者数值后实行之前同样的操作。
四、实验结果图
五、实验源码(基于java)
采用面向对象思想实现,分别建立了GeneticAlgorithm遗传算法类,SpeciesList种群链表类,SpeciesNode物种结点类,Constant常量类,Main主类
1.主函数
publicclassMain{
publicstaticvoidmain(String[]args){
//创建遗传算法驱动对象
GeneticAlgorithmGA=newGeneticAlgorithm();
//创建初始种群
SpeciesListspeciesList=newSpeciesList();
//开始遗传算法(选择算子、交叉算子、变异算子)
SpeciesNodebestRate=GA.run(speciesList);
//打印路径与最短距离
bestRate.printRoute();
}
}
2.Constant类
packageGeneticTSP;
publicclassConstant{
staticintCITY_NUM;//城市数
staticfinalintSPECIES_NUM=2000;//种群数
staticfinalintDEVELOP_NUM=100;//进化代数
staticfinalfloatpcl=0.6f,pch=0.95f;//交叉概率
staticfinalfloatpm=0.4f;//变异概率
staticfinalfloat[][]disMap;//地图数据
static{
int[][]cityPosition={{1304,2312},{3639,1315},{4177,2244},{3712,1399},{3488,1535},
{3326,1556},{3238,1229},{4196,1004},{4312,790},{4386,570},{3007,1970},
{2562,1756},{2788,1491},{2381,1676},{1332,695},{3715,1678},{3918,2179},
{4061,2370},{3780,2212},{3676,2578},{4029,2838},{4263,2931},{3429,1908},
{3507,2367},{3394,2643},{3439,3201},{2935,3240},{3140,3550},{2545,2357},
{2778,2826},{2370,2975}};//31个城市(最优解:
14700)
//路径集合
CITY_NUM=cityPosition.length;
disMap=newfloat[CITY_NUM][CITY_NUM];
for(inti=0;ifor(intj=i;jfloatdis=(float)Math.sqrt(Math.pow((cityPosition[i][0]-cityPosition[j][0]),2)
+Math.pow((cityPosition[i][1]-cityPosition[j][1]),2));
disMap[i][j]=dis;
disMap[j][i]=disMap[i][j];
}
}
}
}
3.GeneticAlgorithm类
packageGeneticTSP;
importjava.util.Random;
publicclassGeneticAlgorithm{
//开始遗传
SpeciesNoderun(SpeciesListlist){
//创建初始种群
createBeginningSpecies(list);
for(inti=1;i<=Constant.DEVELOP_NUM;i++){
//选择
select(list);
//交叉
crossover(list);
//变异
mutate(list);
}
returngetBest(list);
}
//创建初始种群
voidcreateBeginningSpecies(SpeciesListlist){
//100%随机
intrandomNum=(int)(Constant.SPECIES_NUM);
for(inti=1;i<=randomNum;i++){
SpeciesNodespecies=newSpeciesNode();//创建结点
species.createByRandomGenes();//初始种群基因
list.add(species);//添加物种
}
}
//计算每一物种被选中的概率
voidcalRate(SpeciesListlist){
//计算总适应度
floattotalFitness=0.0f;
list.speciesNum=0;
SpeciesNodepoint=list.head.next;//游标
while(point!
=null)//寻找表尾结点
{
point.calFitness();//计算适应度
totalFitness+=point.fitness;
list.speciesNum++;
point=point.next;
}
//计算选中概率
point=list.head.next;//游标
while(point!
=null)//寻找表尾结点
{
point.rate=point.fitness/totalFitness;
point=point.next;
}
}
//选择优秀物种(轮盘赌}
voidselect(SpeciesListlist){
//计算适应度
calRate(list);
//找出最大适应度物种
floattalentDis=Float.MAX_VALUE;
SpeciesNodetalentSpecies=null;
SpeciesNodepoint=list.head.next;//游标
while(point!
=null){
if(talentDis>point.distance){
talentDis=point.distance;
talentSpecies=point;
}
point=point.next;
}
//将最大适应度物种复制talentNum个
SpeciesListnewSpeciesList=newSpeciesList();
inttalentNum=(int)(list.speciesNum/4);
for(inti=1;i<=talentNum;i++){
//复制物种至新表
SpeciesNodenewSpecies=talentSpecies.clone();
newSpeciesList.add(newSpecies);
}
//轮盘赌list.speciesNum-talentNum次
introundNum=list.speciesNum-talentNum;
for(inti=1;i<=roundNum;i++){
//产生0-1的概率
floatrate=(float)Math.random();
SpeciesNodeoldPoint=list.head.next;//游标
while(oldPoint!
=null&&oldPoint!
=talentSpecies)//寻找表尾结点
{
if(rate<=oldPoint.rate){
SpeciesNodenewSpecies=oldPoint.clone();
newSpeciesList.add(newSpecies);
break;
}else{
rate=rate-oldPoint.rate;
}
oldPoint=oldPoint.next;
}
if(oldPoint==null||oldPoint==talentSpecies){
//复制最后一个
point=list.head;//游标
while(point.next!
=null)//寻找表尾结点
point=point.next;
SpeciesNodenewSpecies=point.clone();
newSpeciesList.add(newSpecies);
}
}
list.head=newSpeciesList.head;
}
//交叉操作
voidcrossover(SpeciesListlist){
//以概率pcl~pch进行
floatrate=(float)Math.random();
if(rate>Constant.pcl&&rateSpeciesNodepoint=list.head.next;//游标
Randomrand=newRandom();
intfind=rand.nextInt(list.speciesNum);
while(point!
=null&&find!
=0)//寻找表尾结点
{
point=point.next;
find--;
}
if(point.next!
=null){
intbegin=rand.nextInt(Constant.CITY_NUM);
//取point和point.next进行交叉,形成新的两个染色体
for(inti=begin;i//找出point.genes中与point.next.genes[i]相等的位置fir
//找出point.next.genes中与point.genes[i]相等的位置sec
intfir,sec;
for(fir=0;!
point.genes[fir].equals(point.next.genes[i]);fir++)
;
for(sec=0;!
point.next.genes[sec].equals(point.genes[i]);sec++)
;
//两个基因互换
Stringtmp;
tmp=point.genes[i];
point.genes[i]=point.next.genes[i];
point.next.genes[i]=tmp;
//消去互换后重复的那个基因
point.genes[fir]=point.next.genes[i];
point.next.genes[sec]=point.genes[i];
}
}
}
}
//变异操作
voidmutate(SpeciesListlist){
//每一物种均有变异的机会,以概率pm进行
SpeciesNodepoint=list.head.next;
while(point!
=null){
floatrate=(float)Math.random();
if(rate//寻找逆转左右端点
Randomrand=newRandom();
intleft=rand.nextInt(Constant.CITY_NUM);
intright=rand.nextInt(Constant.CITY_NUM);
if(left>right){
inttmp;
tmp=left;
left=right;
right=tmp;
}
//逆转left-right下标元素
while(leftStringtmp;
tmp=point.genes[left];
point.genes[left]=point.genes[right];
point.genes[right]=tmp;
left++;
right--;
}
}
point=point.next;
}
}
//获得适应度最大的物种
SpeciesNodegetBest(SpeciesListlist){
floatdistance=Float.MAX_VALUE;
SpeciesNodebestSpecies=null;
SpeciesNodepoint=list.head.next;//游标
while(point!
=null)//寻找表尾结点
{
if(distance>point.distance){
bestSpecies=point;
distance=point.distance;
}
point=point.next;
}
returnbestSpecies;
}
}
4.SpeciesList类
packageGeneticTSP;
publicclassSpeciesList{
SpeciesNodehead;//头结点
intspeciesNum;//物种数量
SpeciesList(){
head=newSpeciesNode();
speciesNum=Constant.SPECIES_NUM;
}
//添加物种
voidadd(SpeciesNodespecies){
SpeciesNodepoint=head;//游标
while(point.next!
=null)//寻找表尾结点
point=point.next;
point.next=species;
}
}
5.SpeciesNode类
packageGeneticTSP;
importjava.util.Random;
publicclassSpeciesNode{
String[]genes;//基因序列
floatdistance;//路程
floatfitness;//适应度
SpeciesNodenext;
floatrate;
SpeciesNode(){
//初始化
this.genes=newString[Constant.CITY_NUM];
this.fitness=0.0f;
this.distance=0.0f;
this.next=null;
rate=0.0f;
}
//初始物种基因{随机}
voidcreateByRandomGenes(){
//初始化基因为1-CITY_NUM序列
for(inti=0;igenes[i]=Integer.toString(i+1);
}
//获取随机种子
Randomrand=newRandom();
for(intj=0;jintnum=j+rand.nextInt(genes.length-j);
//交换
Stringtmp;
tmp=genes[num];
genes[num]=genes[j];
genes[j]=tmp;
}
}
//初始物种基因{贪婪}
voidcreateByGreedyGenes(){
Randomrand=newRandom();
inti=rand.nextInt(Constant.CITY_NUM);//随机产生一个城市作为起点
genes[0]=Integer.toString(i+1);
intj;//终点
intcityNum=0;
do{
cityNum++;
//选出单源最短城市
floatminDis=Integer.MAX_VALUE;
intminCity=0;
for(j=0;jif(j!
=i){
//判是否和已有重复
booleanrepeat=false;
for(intn=0;nif(Integer.parseInt(genes[n])==j+1){
repeat=true;//重了
break;
}
}
if(repeat==false)//没重
{
//判长度
if(Constant.disMap[i][j]minDis=Constant.disMap[i][j];
minCity=j;
}
}
}
}
//加入到染色体
genes[cityNum]=Integer.toString(minCity+1);
i=minCity;
}while(cityNum