原材料配送问题的遗传算法实现(C语言)

原材料配送问题的遗传算法实现


1.建立模型
      1.1 问题描述

           有一个原材料供应商,从工厂出发,用一辆货车为若干个下游工厂配送原材料且只配送一次,最后仍回到工厂,问应如何选择行车路线,使总耗油量最少。模型的基本假设:

                a.货车的载重量无限大。
                b.货车行驶路面的粗糙程度相同并且无上下坡。
                c.货车的耗油量只与货车的载重量和行驶路程决定,其他因数忽略不计。

      1.2 模型推导(通过截图体现)

          耗油量的多少可以用货车在整个过程中做功的多少来衡量,

   《原材料配送问题的遗传算法实现(C语言)》

      《原材料配送问题的遗传算法实现(C语言)》

   《原材料配送问题的遗传算法实现(C语言)》

   《原材料配送问题的遗传算法实现(C语言)》

   《原材料配送问题的遗传算法实现(C语言)》

   《原材料配送问题的遗传算法实现(C语言)》

        (PS:将这个问题完整描述将有助于整个算法的理解)

     1.3 模型目标
       在本模型中,在每一行或每一列中各取一个值得到货车的一条行车路径,共有n!种货车行驶路线(n为下游工厂数量),目标是通过有限次计算,寻找一条行车路径,使总的耗油量相对最低。

     1.4 模型分析
      本问题的组合情况数量为n!,其中还未考虑其中每一种情况本身的计算量。
      当n=10,n!=3628800;
      当n=20,n!=2.432902e+18;
      当n=50,n!=3.041409e+64;
      当n=100,n!=9.332622e+157;
       ……
      当n=100时,一般个人计算机的频率约为2GHz,这样需要持续计算n!/(2*e+9)=4.666311e+148秒~1.479677e+141 年,列举所有情况将产生组合爆炸,要穷举所有的情况基本是不可能的,这也是一类典型的np-hard问题。当n很大时,按照常规的方法根本没法解决此类问 题,一般用启发式算法来解决此类问题,常用的启发式算法有:遗传算法、模拟退火算法、禁忌搜索算法、蚁群算法等,但启发式算法也只能获得相对最优解,继上次用蚁群算法实现这个模型之后(参见:原材料配送问题的蚁群算法实现),我将用遗传算法(Genetic Algorithm )来解决本问题。

2.遗传算法(Genetic Algorithm )
     2.1 基本思想
        遗传算法(Genetic Algorithms,简称GA)是J.HolIand于1975年受生物进化论的启发而提出的。遗传算法是建立在自然选择和遗传理论基础上,将生物进化过程中适者生存规则与同一群染色体的随机信息变换机制相结合的一种高度并行、随机和自适应的优化算法。

     2.2算法核心环节

      本节将介绍遗传算法实现过程中的核心环节,包括:编码、交叉、变异、交叉变异个体的概率分配,这部分涉及到公式和特殊字符,就直接上MS Word上编辑好,直接通过截图体现。

     2.2.1编码Encoding

   《原材料配送问题的遗传算法实现(C语言)》

     2.2.2 交叉 Crossover

   《原材料配送问题的遗传算法实现(C语言)》

   《原材料配送问题的遗传算法实现(C语言)》

     2.2.3 变异 Mutation

《原材料配送问题的遗传算法实现(C语言)》

     2.2.4 交叉变异个体的概率分配

   《原材料配送问题的遗传算法实现(C语言)》

   《原材料配送问题的遗传算法实现(C语言)》

  
   2.3 算法流程
    本问题的蚁群算算法的流程图为:

            《原材料配送问题的遗传算法实现(C语言)》  

     2.4 C语言实现
       我用C语言通过遗传算法解决本问题,c语言实现的代码如下,共有两个文件,GA.H:记录一些全局常量和函数声明,GA.c为主要实现文件。
      GA.H和  ACO.c的代码:  

/*
 ============================================================================
 Name        : GA.c
 Author      : sheng
 Description : 本例通过遗传算法解决原材料配送这个np-hard问题,求出了一组相对
               最优解以及一组参照解。
 ============================================================================
 */
#include 
#include 
#include 
#include 
#include "GA.H"
int main(){
	int j,k;
	int fittnessOrder;
	struct factory  factoryInfo[FACTORY_COUNT+1];    //定义每个工厂(包括原材料配送中心)的信息
	struct route  population[INIT_POPULATION_NUM];   //定义种群每个个体的路径
	fittnessOrder=10;   //结果输出按适应度大小降序排列的前fittnessOrder位
	Init_Factory_Information(factoryInfo);
	Init_Population(population,factoryInfo);
        Evaluate_Population(population,factoryInfo);
	for (k=0;k");
	  	else printf("\n");
	}
	printf("\n");
	printf("2.The relative optimal individual: \n");
	printf("The fittness: %f\n",((1/population[0].fittness)*1000*FRICTION_RATIO));//输出相对最优种群个体的适应度
	printf("The route: ");
	for(j=0;j");
	        else printf("\n");
	}
	return EXIT_SUCCESS;
}
/*
============================================================================
Function Name:Crossover
Function     :种群个体交叉操作,产生新的子代
============================================================================
*/
void Crossover(struct route *population){
	int i;
	int crossvoerIndividualA,crossvoerIndividualB;  //交叉的两个个体
	int crossoverPosition[2]={0};            //交叉变异的起始地址和长度
	for (i=0;i9);
	return ;
}
/*
============================================================================
Function Name:Evaluate_Population
Function     :评估种群,产生适应度和按适应度排序的结果
============================================================================
*/
void Evaluate_Population(struct route *population,struct factory *factoryInfo){
	int i,j,k,routeChange;             //routeChange交换路径信息的中间变量
	double fittnessChange;              //交换适应度的中间变量
	for (j=0;j

      数据来源说明:本例子中的FACTORY_COUNT个工厂的位置、以及各个工厂的需求数据(共FACTORY_COUNT*3个数)均是通过OpenOffice Calc的随机数生成的。
      FACTORY的X与Y坐标生成算式均为:IF(RAND()>0.5;ROUND((RAND()* (1000-100)+100);2);-ROUND((RAND()*(1000-100)+100);2))。X与Y坐标代有正负,生成的正负值的概 率基本相等,式子中的三个RAND()函数在每一次都是独立取值的,说明了本数据服从(-1000,100)U(100,1000)之间的均匀分布,配送 中心的坐标为(0,0)。
    FACTORY的需求生成算式:ROUND((RAND()*(100-10)+10);2)。各个下游工厂的需求量服从(10,100)之间的均匀分布,保留两个有效数字,配送中心的需求为0。
    本例中数据没能直观的体现数据本身的意义,只是将其用到本问题算法的验证中。代码参数说明:本例中存在许多全局参数设置,如 INIT_POPULATION_NUM,GENERATION_NUM,POPULATION_PARENT_NUM,POPULATION_CHILDREN_NUM,MUTATION_NUM等,比较重要的参数为,INIT_POPULATION_NUM表示种群个体总数数,这个参数直接决定了问题的规模,种群个体总数需要根据所解决的问题和计算机的硬件配置选择,这个参数设定的太大会造成内存不足,但设定的太小,会造成难于收敛,不能求出可接受的相对最优解; GENERATION_NUM表示迭代次数,从一定程度上来说,迭代的次数越多越好,但一旦出现早熟后,此时迭代只是浪费系统资源,不会对结果产生影响; POPULATION_PARENT_NUM表示每一代没有进行交叉变异的个体数量,与 POPULATION_CHILDREN_NUM相对,POPULATION_CHILDREN_NUM表示每一代进行了交叉变异的个体数量, POPULATION_PARENT_NUM设定的越大,越容易收敛甚至是早熟;MUTATION_NUM表示同一条染色体上变异次数的取值范围为(0,MUTATION_NUM),通过随机数决定这个参数的具体值。

  C语言实现的输出结果:

   《原材料配送问题的遗传算法实现(C语言)》
       由于使用启发式算法解决np-hard问题,几乎不可能得到最优解,在本例中,随着参数(全局常量)设置的不同,结果不相同,即使在参数设置相同的情况下,运行的结果也很难相同,但遗传算法一旦早熟之后,每个个体的染色体都是相同的,最终出现每个种群个体的路径都相同的情况。 第一组结果表示其中的第POPULATION_PARENT_NUM个个体(种群中第一个从上一代变异而来的个体)的适应度和染色体编号(行车路线)。第二组结果表示通过遗传算法得出的相对最优解,比上面随机选择一组的结果要好,后面的一组线路图表示相对最优解所对应的行车路线(染色体编号),该线路表示从配送中心(0,0)出发,经过FACTORY_COUNT个(本例中是100个)下游工厂后回到配送中心(0,0)。


总结:本例通过遗传算法解决原材料配送这个np-hard问题,通过C语言实现了基本的遗传算法并求出了一组相对最优解,本算例的参数选择较蚁群算法简单,实际操作的时候很容易造成内存不足问题,代码上体现地很详细。但是本文对算法中参数选择、数据选择以及最终结果的解释没能做有效地分析,只是做了部分尝试,这需要后续不断地修正和改进。

PS:本算例是我在大二时候实现的,本文模板是参照前几天写的博客:原材料配送问题的蚁群算法实现(C语言) ,这两个实现方式针对同一问题,模板就直接Copy了,希望这个简单的模型及其遗传和蚁群算法实现,能够加深读者对于蚁群算法、遗传算法等启发式算法的理解。


参考:

[1] 柳林,朱建荣. 基于遗传算法的物流配送路径优化问题的研究. 计算机工程与应用,2005 年第41 卷第27 期:227-229.
[2] 郎茂祥,胡思继. 用混合遗传算法求解物流配送路径优化问题的研究. 中国管理科学,2002,10(10):51-56.
[3] 鲁燃,马学强,潘美芹. 利用遗传算法搜索全局最优的一种混合算法. 山东师范大学报(自然科学版),2000,15(4)

    原文作者:遗传算法
    原文地址: https://blog.csdn.net/u013259893/article/details/38226489
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞