很早以前在初等数学建模里碰到一个例子,给定n(n>=3)个顶点,求平面上的一个点或多个点,使得所有点连通,并且点到点的距离之和最小,书上给出了一个定理,就是当这些点与点的连线 的夹角都是120度时,可以证明 距离是最小的。当n=3时,只需一个点即可,并且可以通过几何的方法 轻易地找出,但是随着 n规模的增大,问题的复杂度将不可预测,而且没有一个有效地方法解决这个问题。恰巧当时学了遗传算法,就用它 求解。遗传算法可以在有限的时间内 找到一个最优近似解。

用遗传算法求解 ,必须解决三个问题,

第一 基因初始种类 我们说 好马才能生出 良驹 ,好的基因初始种类 可以缩短 基因的遗传代数 从而降低算法的复杂度。但是这个 好不能是主观上的好,即便是理论上的,也最好 对种类进行混搭 。

第二 最重要的就是基因的编码, 即设计一种较好的数据结构,这个数据结构需要尽量将每一个 独立因子分离出来,因子的数量不能太多,不然问题的复杂度就太大,也不能太少,这样就无法得到最优基因序列。具体可以参考多元统计分析里的因子分析理论,除此之外,基因在设计时还要考虑 便于衡量整个基因的好坏,因为我们要对基因进行优胜劣汰;

第三 基因的变异与交叉 也是十分重要的,变异是为了克服初始规模太小和最优因子序列遗失 从而避免过早收敛于局部最优解,这个变异的度必须把握好;交叉是为了获得最优因子序列重而获得最优基因。

本文以n=3为例 用遗传算法求解 ,这是最简单的一种情况。不需要 对基因,变异和交叉 进行严格设计。但是整个遗传算法的流程和思路是一样的,废话不多 上代码:




View Code


1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<ctime>
 6 using namespace std;
 7 //***************************************************************************
 8 //This is a simple genetic algorithm implementation for function optimization
 9 //参考书籍 《人工智能原理与应用》 金聪 清华大学出版社 2009
10 //Freeze 于2010 7 7
11 
12 //Problem describing:assuming that there are three point in the plane xOy
13 //which located at O(0,0),P(12,0),Q(8,6).
14 //please find Point R to let W=5|RO|+4|RP|+3|RQ| reach the minimum value
15 //***************************************************************************
16 //Parametes setting                      
17 #define POPSIZE 200     //population size 
18 #define MAXGENS 1000    //max number of generation 
19 #define NVARS 2         //no of problem variables  
20 #define PXOVER    0.75  //probalility of crossover  
21 #define PMUTATION 0.15  //probalility of mutation  
22 #define TRUE 1
23 #define FALSE 0
24 #define LBOUND 0       
25 #define UBOUND 12      
26 #define STOP 0.001
27 int generation;         //current generation no
28 int cur_best;           //best individual
29 double diff;            
30 FILE *galog;            //an output file
31 struct genotype
32 {
33     double gene[NVARS];     //a string of variables基因变量
34     double upper[NVARS];    //individual's variables upper bound 基因变量取值上确界
35     double lower[NVARS];    //individual's batiables lower bound 基因变量取值下确界
36     double fitness;         //individual's fitness个体适应值
37     double rfitness;        //relative fitness个体适应值占种群适应值比例
38     double cfitness;        //curmulation fitness个体适应值的累加比例
39 };
40 struct genotype population[POPSIZE+1]; 
41 //population 当前种群 population[POPSIZE]用于存放个体最优值并假设最优个体能存活下去
42 //在某些遗传算法中最优值个体并不一定能够存活下去
43 struct genotype newpopulation[POPSIZE+1]; //new population replaces the old generation 子种群
44 /*Declaration of procedures used by the gentic algorithm*/
45 void initialize(void);                    //初始化函数
46 double randval(double,double);            //随机函数
47 double funtion(double x1,double x2);    //目标函数
48 void evaluate(void);                    //评价函数
49 void keep_the_best(void);                //保留最优个体
50 void elitist(void);                        //当前种群与子代种群最优值比较
51 void select(void);
52 void crossover(void);                    //基因重组函数
53 void swap(double *,double *);            //交换函数
54 void mutate(void);                        //基因突变函数
55 double report(void);                    //数据记录函数




View Code


1 //**************************************************************************************
  2 //Initializaton function:Initalizes the values of genes within the variables 
  3 //bounds.It also initializes all fitness values for each number of the population
  4 //**************************************************************************************
  5 void initialize(void)
  6 {
  7     int i,j;
  8     for(i=0;i<NVARS;i++)
  9     {
 10         for(j=0;j<POPSIZE+1;j++)
 11         {
 12             if(!i)
 13             {
 14                 population[j].fitness=0;
 15                 population[j].rfitness=0;
 16                 population[j].cfitness=0;
 17             }
 18             population[j].lower[i]=LBOUND;
 19             population[j].upper[i]=UBOUND;
 20             population[j].gene[i]=randval(population[j].lower[i],population[j].upper[i]);
 21         }
 22     }
 23 }
 24 //***************************************************************************
 25 //Random value generator:generates a value within bounds
 26 //***************************************************************************
 27 double randval(double low,double high)
 28 {
 29     double val;
 30     val=((double)(rand()%10000)/10000)*(high-low)+low;
 31     return val;
 32 }
 33 //目标函数
 34 double funtion(double x,double y)
 35 {
 36     double result1=sqrt(x*x+y*y)+sqrt((x-12)*(x-12)+y*y)+sqrt((x-8)*(x-8)+(y-6)*(y-6));
 37     return result1;
 38 }
 39 //***************************************************************************
 40 //Evaluation function:evaluate the individual's fitness.评价函数给出个体适应值
 41 //Each time the function is changes,the code has to be recompl
 42 //***************************************************************************
 43 void evaluate(void)
 44 {
 45     int mem;
 46     int i;
 47     double x[NVARS];
 48     for(mem=0;mem<POPSIZE;mem++)
 49     {
 50 
 51         for(i=0;i<NVARS;i++)
 52             x[i]=population[mem].gene[i];
 53         population[mem].fitness=funtion(x[0],x[1]);//将目标函数值作为适应值
 54     }
 55 }
 56 //***************************************************************************************
 57 //Keep_the_best function:This function keeps track of the best member of the population.
 58 //找出种群中的个体最优值并将其移动到最后
 59 //***************************************************************************************
 60 void keep_the_best()
 61 {
 62     int mem;
 63     int i;
 64     cur_best=0;
 65     for(mem=0;mem<POPSIZE;mem++)//找出最高适应值个体
 66     {
 67         if(population[mem].fitness<population[cur_best].fitness)
 68         {
 69             cur_best=mem;            
 70         }
 71     }
 72     //将最优个体复制至population[POSIZE]
 73     if(population[cur_best].fitness<=population[POPSIZE].fitness||population[POPSIZE].fitness<1)//防止出现种群基因退化 故保留历史最优个体
 74     {
 75         population[POPSIZE].fitness=population[cur_best].fitness;
 76         for(i=0;i<NVARS;i++)
 77             population[POPSIZE].gene[i]=population[cur_best].gene[i];
 78     }    
 79 }
 80 //***************************************************************************
 81 //Elitist function:The best member of the previous generation is stored as the
 82 //last in the array.If the best individual from  the new populatin is better
 83 //than the best individual from the previous population ,then copy the best
 84 //from the new population;else replace the worst individual from the current
 85 //population with the best one from the previous generation.防止种群最优值退化
 86 //***************************************************************************
 87 void elitist()
 88 {
 89     int i;
 90     double best,worst;//适应值
 91     int best_mem,worst_mem;//序号
 92     best_mem=worst_mem=0;
 93     best=population[best_mem].fitness;//最高适应值初始化
 94     worst=population[worst_mem].fitness;//最低适应值初始化
 95     for(i=1;i<POPSIZE;i++)//找出最高和最低适应值 算法有待改进
 96     {        
 97         if(population[i].fitness<best)
 98         {
 99             best=population[i].fitness;
100             best_mem=i;
101         }
102         if(population[i].fitness>worst)
103         {
104             worst=population[i].fitness;
105             worst_mem=i;
106         }    
107     }
108     if(best<=population[POPSIZE].fitness)//赋值
109     {
110         for(i=0;i<NVARS;i++)
111             population[POPSIZE].gene[i]=population[best_mem].gene[i];
112         population[POPSIZE].fitness=population[best_mem].fitness;
113     }
114     else
115     {
116         for(i=0;i<NVARS;i++)
117             population[worst_mem].gene[i]=population[POPSIZE].gene[i];
118         population[worst_mem].fitness=population[POPSIZE].fitness;
119     }
120 }
121 //***************************************************************************
122 //Select function:Standard proportional selection for maximization problems
123 //incorporating elitist model--makes sure that the best member survives.筛选函数并产生子代
124 //***************************************************************************
125 void select(void)
126 {
127     int mem,i,j;
128     double sum=0;
129     double p;
130     for(mem=0;mem<POPSIZE;mem++)//所有适应值求和
131     {
132         sum+=population[mem].fitness;
133     }
134     for(mem=0;mem<POPSIZE;mem++)
135     {
136         population[mem].rfitness=population[mem].fitness/sum;//个人认为还不如建一个种群类 把sum看成类成员
137     }
138     population[0].cfitness=population[0].rfitness;
139     for(mem=1;mem<POPSIZE;mem++)
140     {
141         population[mem].cfitness=population[mem-1].cfitness+population[mem].rfitness;
142     }
143     for(i=0;i<POPSIZE;i++)
144     {
145         p=rand()%1000/1000.0;
146         if(p<population[0].cfitness)
147         {
148             newpopulation[i]=population[0];
149         }
150         else
151         {
152             for(j=0;j<POPSIZE;j++)
153                 if(p>=population[j].cfitness&&p<population[j+1].cfitness)
154                     newpopulation[i]=population[j+1];
155         }
156     }
157     for(i=0;i<POPSIZE;i++)//子代变父代
158         population[i]=newpopulation[i];
159 }





View Code


1 //***************************************************************************
  2 //Crossover:performs crossover of the selected parents.
  3 //***************************************************************************
  4 void Xover(int one,int two)//基因重组函数
  5 {
  6     int i;
  7     int point;
  8     if(NVARS>1)
  9     {
 10         if(NVARS==2)
 11             point=1;
 12         else
 13             point=(rand()%(NVARS-1))+1;//两个都重组吗?
 14         for(i=0;i<point;i++)//只有第一个基因发生重组有待改进
 15             swap(&population[one].gene[i],&population[two].gene[i]);
 16     }
 17 }
 18 //***************************************************************************
 19 //Swapp: a swap procedure the helps in swappling 2 variables
 20 //***************************************************************************
 21 void swap(double *x,double *y)
 22 {
 23     double temp;
 24     temp=*x;
 25     *x=*y;
 26     *y=temp;
 27 }
 28 //***************************************************************************
 29 //Crossover function:select two parents that take part in the crossover.
 30 //Implements a single point corssover.杂交函数
 31 //***************************************************************************
 32 void crossover(void)
 33 {
 34     int mem,one;
 35     int first=0;
 36     double x;
 37     for(mem=0;mem<POPSIZE;++mem)
 38     {
 39         x=rand()%1000/1000.0;
 40         if(x<PXOVER)
 41         {
 42             ++first;
 43             if(first%2==0)//选择杂交的个体对 杂交有待改进 事实上往往是强者与强者杂交 这里没有考虑雌雄与杂交对象的选择
 44                 Xover(one,mem);
 45             else
 46                 one=mem;
 47         }
 48     }
 49 }
 50 //***************************************************************************
 51 //Mutation function:Random uniform mutation.a variable selected for mutation
 52 //变异函数 事实基因的变异往往具有某种局部性
 53 //is replaced by a random value between lower and upper bounds of the variables.
 54 //***************************************************************************
 55 void mutate(void)
 56 {
 57     int i,j;
 58     double lbound,hbound;
 59     double x;
 60     for(i=0;i<POPSIZE;i++)
 61         for(j=0;j<NVARS;j++)
 62         {
 63             x=rand()%1000/1000.0;
 64             if(x<PMUTATION)
 65             {
 66                 lbound=population[i].lower[j];
 67                 hbound=population[i].upper[j];
 68                 population[i].gene[j]=randval(lbound,hbound);
 69             }
 70         }
 71 }
 72 //***************************************************************************
 73 //Report function:Reports progress of the simulation.
 74 //***************************************************************************
 75 double report(void)
 76 {
 77     int i;
 78     double best_val;//种群内最优适应值
 79     double avg;//平均个体适应值
 80     //double stddev;
 81     double sum_square;//种群内个体适应值平方和
 82     //double square_sum;
 83     double sum;//种群适应值
 84     sum=0.0;
 85     sum_square=0.0;
 86     for(i=0;i<POPSIZE;i++)
 87     {
 88         sum+=population[i].fitness;
 89         sum_square+=population[i].fitness*population[i].fitness;
 90     }
 91     avg=sum/(double)POPSIZE;
 92     //square_sum=avg*avg*(double)POPSIZE;
 93     //stddev=sqrt((sum_square-square_sum)/(POPSIZE-1));
 94     best_val=population[POPSIZE].fitness;
 95     fprintf(galog,"%6d  %6.3f  %6.3f  %6.3f  %6.3f  %6.3f\n",generation,best_val,population[POPSIZE].gene[0],population[POPSIZE].gene[1],avg,sum);
 96     return avg;
 97 }
 98 //***************************************************************************
 99 //main function:Each generation involves selecting the best members,performing
100 //crossover  & mutation and then evaluating the resulting population,until the
101 //terminating condition is satisfied.
102 //***************************************************************************
103 void main(void)
104 {
105     int i;
106     double temp;
107     double temp1;
108     if((galog=fopen("data.txt","w"))==NULL)
109     {
110         exit(1);
111     }
112     generation=1;
113     srand(time(NULL));
114     fprintf(galog,"number  value    x1      x2     avg     sum_value\n");
115     printf("generation best average standard\n");
116     initialize();
117     evaluate();
118     keep_the_best();
119     temp=report();//记录,暂存上一代个体平均适应值    
120     do
121     {            
122         select();//筛选
123         crossover();//杂交
124         mutate();//变异
125         evaluate();//评价
126         keep_the_best();//elitist();
127         temp1=report();
128         diff=fabs(temp-temp1);
129         temp=temp1;
130         generation++;
131     }while(generation<MAXGENS&&diff>=STOP);
132     //fprintf(galog,"\n\n Simulation completed\n");
133     //fprintf(galog,"\n Best member:\n");
134     printf("\nBest member:\ngeneration:%d\n",generation);
135     for(i=0;i<NVARS;i++)
136     {
137         //fprintf(galog,"\n var(%d)=%3.3f",i,population[POPSIZE].gene[i]);
138         printf("X%d=%3.3f\n",i,population[POPSIZE].gene[i]);
139     }
140     //fprintf(galog,"\n\n Best fitness=%3.3f",population[POPSIZE].fitness);
141     fclose(galog);
142     printf("\nBest fitness=%3.3f\n",population[POPSIZE].fitness);
143 }



我相信对于那些没有 直接有效算法的最优值求解 使用遗传算法将是一个不错的选择。