遗传算法——旅行商问题

 

遗传算法-旅行商问题

 

       旅行商问题:一个旅行者要去很多城市,每个城市只去一次,问:该怎么走路线最短?

 

       这个问题可以转化为:随机给n个点,如何连线这n个点,使得连线最短?

 

       这个问题是遗传算法的经典问题~哈哈~~我试着写了一个程序来解决。

 

       采用的策略是:

1.       精英主义:每次有2个最优解直接进入下一代。

2.       轮盘赌选择生育:每次对每一代的个体进行一次轮询,如果不适应度<某个随机数,那么选择这个个体进行生育。

3.       单性繁殖:因为基因组的基因是互斥的且有序的,所以不适合两性繁殖。

4.       交换变异:变异的方式为——随机选择两个不同位置的基因,交换位置。

 

 

mfc写的,截图:呵呵。变异率不用填,我写死在程序里了。

写了这个程序之后,我深刻地理解到,所谓遗传算法,就是搜索局部最优解的算法。并且他假定较优解的周围出现较优解的几率比较大!遗传算法的目的,就是找到一个可能最优的解!为了达到这个目的,他先对解进行随机搜索,然后选中几个解中较优的解,进行一些变换,然后再次从这些变换后的解中搜寻较优解,变换n次之后,有可能得到非常优秀的解。

所以说,遗传算法是建立在最优解与较优解的差别小的基础上的,也可以说,是建立在父母漂亮,小孩很有可能也漂亮的理论基础上的。

另外,遗传算法也是拼人品的算法,他得出的很有可能是局部最优解,而不是全局最优解。


修改后的源代码:

http://download.csdn.net/source/914702


下载代码后,请把GAMachine.cpp里的代码做一些更改:
  1. void cGAMachine::SetupNextGeneration()//进化到下一代
  2. {
  3.    vector<cGenome> offspring;//保存下一代基因
  4.      
  5.    m_maxNotFitness = m_genomes[m_population - 1].m_notfitness;//所有基因组最大不适应度
  6.      
  7.     
  8.    while (offspring.size() < (unsigned int)m_population - 2)//选择(最大人口数-2)数量的基因组进行变异和遗传
  9.    {
  10.          cGenome parent = SelectRouletteWheel();//进行轮盘赌随机选择一个基因组出来进行生育
  11.          cGenome offspring1;//保存变异后的基因组
  12.          MutateInsert(parent.m_genes, offspring1.m_genes);//进行变异
  13.          offspring.push_back(offspring1);//将变异后的基因组压入第二代vector<基因组>里
  14.      }
  15.      sort(m_genomes.begin(), m_genomes.end());//对vector<基因组>进行排序,以便下一行代码选出最优秀的2个基因组
  16.      CopyEliteInto(offspring);//直接将最优秀的2个基因组复制到下一代
  17.      m_genomes = offspring;
  18.      
  19.      m_curGener++;//代数计数器+1
  20.  }
  1. void cGAMachine::MutateInsert(const vector<cGene> &parent, vector<cGene> &offspring)//插入变异,感觉比交换变异更好
  2. {
  3.     /*if (rand() / (double)(RAND_MAX) > m_mutationRate)
  4.     {
  5.         offspring = parent;
  6.         return;
  7.     }*/
  8.     int nRandscr = rand() % (parent.size() - 1);
  9.     int nRanddes = rand() % (parent.size() - 1);
  10.     if (nRanddes == nRandscr)
  11.     {
  12.         offspring = parent;
  13.         return;
  14.     }
  15.     cGene geneInsert = parent[nRandscr];
  16.     offspring = parent;
  17.     offspring.erase(offspring.begin() + nRandscr);
  18.     if (nRandscr < nRanddes)
  19.     {
  20.         offspring.insert(offspring.begin() + nRanddes - 1, geneInsert);
  21.     }
  22.     else
  23.     {
  24.         offspring.insert(offspring.begin() + nRanddes, geneInsert);
  25.     }
  26. }


介绍一下个文件功能

我这个程序的思想是,随机生成“地点数”编辑框输入的数字的地点,存储在一个vector里。然后用一个“基因类”表示该基因代表第几个点,接着一个“基因组类”有序包含了很多“基因类”,如果一个“基因组类”包含的基因类顺序为:基因组.基因【0.data = 第二个点;基因组.基因【1.data = 第三个点;基因组.基因【3.data = 第一个点;就说明该基因组表示的连线顺序是从第二点连到第三个点再连到第一个点。

 

接着有一个“遗传机器类”包含了很多基因组。基因组的数量由“人口数”编辑框决定。初始化的时候,每个基因组的基因顺序是随机决定的。进行第一代进化的时候,遍历vector<基因组>,计算每个基因组代表的连线方式的连线长度。连线长度越长,说明这个基因组越差劲,因为我们要计算以何种方式连线连线长度最短。我们用不适应度来记录连线长度。

 

接着就是选择哪个基因组可以生育,遗传给下一代。我采用了一个轮盘赌的策略,尽可能选择不适应度低的基因组进行生育。

 

选择出的基因组进行交换变异后,就把这个基因组复制给下一代。

 

最后,选择两个最好的基因组,不进行任何变异,直接复制到下一代。

 

这样循环反复,迭代“代数”编辑框输入的代数次数之后,就可以输出结果了。

 

结果就是最后一代最优秀的那个基因组代表的连线方式。

 

 

首先Gene.h,这个文件包含了基因类,用来存储该基因代表第几个点

其次Genome.h,这个文件包含了基因组类,他存储了很多基因顺序

再次GAMachine.h,这个文件包含了遗传机器类。



阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页