算法设计与分析题目练习五:求最大值(遗传算法)
2016-12-24 11:43
633 查看
人工智能--遗传算法 求解f (x) = x2 的最大值,x∈ [0,31]
/*********************************************************** ** 人工智能--遗传算法 ** ** 求解f (x) = x2 的最大值,x∈ [0,31] ** ** /**********************************************************/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #define TEST 0 //0:屏蔽所有的调试信息 1:开启所有的调试信息 #define TEST_FLAG 4 //1:测试randCreatePop函数 2:测试selection函数 //3.测试crossover函数 4.测试mutation函数 #define CROSS_RATE 0.5 //变异率(mutation rate)取值范围一般为0.4~0.99 #define MUT_RATE 0.09 //变异率(mutation rate)取值范围一般为0.0001~0.1 #define ITER_NUM 1000 //迭代次数(iteration number) #define POP_NUM 4 //初始化种群的个数 #define GENE_NUM 5 //基因的位数个数 #define FUN_EXP(x) ((x)*(x)) //函数表达式 typedef unsigned int UINT; //染色体的数据结构 typedef struct{ char geneBit[GENE_NUM]; //基因位(gene bit)表示方式 UINT fitValue; //适应值(fittness value)(衡量个体的优劣) }Chromosome; void randCreatePop(Chromosome *); //随机创建初始群体 void selection(Chromosome *); //选择(Selection):根据适应度选择优良个体(最优解) void crossover(Chromosome *); //交叉(Crossover):染色体的片断(基因)进行交换 void mutation(Chromosome *); //变异(Mutation) :随机改变染色体片断(基因)的值 void updatePop(Chromosome *, Chromosome *);//更新种群 void printResult(Chromosome *); //打印结果(当x为何值时,f(x)最大) UINT calcFitValue(UINT); //计算染色体的适应度值 UINT binToDec(Chromosome); //将类似二进制的基因位转化为十进制 void test(Chromosome *); //测试函数 int main(int argc, char *argv[]) { int count; // 记录迭代次数 Chromosome curPop[POP_NUM]; // 初始种群 Chromosome nextPop[POP_NUM]; // 更新后种群 //随机创建初始群体 randCreatePop(curPop); //开始迭代 for (count = 1; count < (ITER_NUM + 1); count++) { updatePop(curPop, nextPop); // 更新种群 selection(nextPop); // 挑选优秀个体 crossover(nextPop); // 交叉得到新个体 mutation(nextPop); // 变异得到新个体 updatePop(nextPop, curPop); // 种群更替 printf("\n第%d代迭代的结果:\n", count); // 输出当前迭代次数,即种群的代数 test(curPop); //输出结果 }//迭代结束 printResult(curPop); //打印结果(当x为何值时,f(x)最大) system("pause"); return 0; }//end of main //创建初始群体 void randCreatePop(Chromosome *pop) { UINT i, j; UINT randValue; UINT value; srand((unsigned)time(NULL)); //如果所有的函数都要使用到rand函数,只需要在先运行的函数使用一次srand即可 for (i = 0; i < POP_NUM; i++) // 从种群中的第1个染色体到第POP_NUM个染色体 { for (j = 0; j < GENE_NUM; j++) // 从染色体的第1个基因位到第GENE_NUM个基因位 { randValue = rand() % 2; // 随机产生0或者1 pop[i].geneBit[j] = randValue + '0'; // 将随机数(0,1)赋给基因位 } value = binToDec(pop[i]); // 计算染色体基因对应的值 pop[i].fitValue = calcFitValue(value); // 计算染色体的适应度值 } #if (TEST==1) && (TEST_FLAG==1) //测试 printf("\n随机分配的种群如下:\n"); test(pop); #endif }//end of createPop //选择(Selection):根据适应度选择优良个体(最优解) void selection(Chromosome *pop) { UINT i, j; UINT sumFitValue; //总适应值 UINT avrFitValue; //平均适应值 float choicePro[POP_NUM]; //选择机会 Chromosome tempPop; //临时种群变量 #if (TEST==1) && (TEST_FLAG==2) //测试 printf("\n没有选择前的种群如下:\n"); test(pop); #endif // 根据个体适应度来排序(冒泡法) 降序 for (i = POP_NUM; i > 0; i--) { for (j = 0; j<(i - 1); j++) { if (pop[j + 1].fitValue > pop[j].fitValue) { tempPop = pop[j + 1]; pop[j + 1] = pop[j]; pop[j] = tempPop; } } } //计算出总适应值 sumFitValue = 0; for (i = 0; i < POP_NUM; i++) { sumFitValue += pop[i].fitValue; } //计算出平均适应值(四舍五入,保留到小数点后1位) avrFitValue = (UINT)(((float)sumFitValue / POP_NUM) + 0.5); //计算出每个群体选择机会 for (i = 0; i < POP_NUM; i++) //群体的概率 = 群体适应值/总适应值 { //平均概率 = 平均适应值/总适应值 //群体选择机会 = (群体的概率/平均概率) choicePro[i] = ((float)pop[i].fitValue / sumFitValue) / ((float)avrFitValue / sumFitValue); choicePro[i] = (float)((int)(choicePro[i] * 100 + 0.5) / 100.0);//保留到小数点后2位,四舍五入 } //根据选择概率来繁殖(copy)优良个体、淘汰较差个体 //如果choicePro[i]==0淘汰复制一次最优的群体 for (i = 0; i < POP_NUM; i++) { if (((int)(choicePro[i] + 0.55)) == 0) pop[POP_NUM - 1] = pop[0]; } #if (TEST==1) && (TEST_FLAG==2) //测试 printf("\n经过选择的种群如下:\n"); test(pop); #endif }//end of selection //交叉(Crossover):染色体的片断(基因)进行交换 void crossover(Chromosome *pop) { char tmpStr[GENE_NUM] = ""; UINT i; UINT randPos; UINT randValue; // srand( (unsigned)time( NULL ) ); randValue = rand() % 100; // 随机产生0到49之间的数; if (randValue >= (int)(CROSS_RATE * 100)) // randValue<50的概率只有50%,即变异率为0.5 { #if (TEST==1) && (TEST_FLAG==3) //测试 printf("\n种群没有进行交叉.\n"); #endif return; } #if (TEST==1) && (TEST_FLAG==3) //测试 printf("\n交叉前,种群如下:\n"); test(pop); printf("\n交叉的位置依次为:"); #endif //种群中个体染色体两两交叉 for (i = 0; i < POP_NUM; i += 2) { //crossover child i and child i+1 randPos = (rand() % (GENE_NUM - 1) + 1); // 随机产生交叉点,交叉点控制在1到(GENE_NUM-1)之间 strncpy(tmpStr, pop[i].geneBit + randPos, GENE_NUM - randPos); strncpy(pop[i].geneBit + randPos, pop[i + 1].geneBit + randPos, GENE_NUM - randPos); strncpy(pop[i + 1].geneBit + randPos, tmpStr, GENE_NUM - randPos); #if (TEST==1) && (TEST_FLAG==3) //测试 printf(" %d", randPos); #endif } // 为新个体计算适应度值 for (i = 0; i < POP_NUM; i++) { pop[i].fitValue = calcFitValue(binToDec(pop[i])); } #if (TEST==1) && (TEST_FLAG==3) //测试 printf("\n交叉后,种群如下:\n"); test(pop); #endif }//end of crossover //变异(Mutation) :随机改变染色体片断(基因)的值 void mutation(Chromosome *pop) { UINT randRow, randCol; UINT randValue; // srand( (unsigned)time( NULL ) ); randValue = rand() % 100; // 随机产生0到99之间的数; if (randValue >= (int)(MUT_RATE * 100)) // randValue<2的概率只有2%,即变异率为0.02 { #if (TEST==1) && (TEST_FLAG==4) //测试 printf("\n种群中没有基因变异.\n"); #endif return; } randCol = rand() % GENE_NUM; // 随机产生要变异的基因位号 randRow = rand() % POP_NUM; // 随机产生要变异的染色体号 #if (TEST==1) && (TEST_FLAG==4) //测试 printf("\n变异前,种群如下:\n"); test(pop); printf("\n变异的位置:染色体号=%d 基因位号=%d\n", randRow + 1, randCol); #endif pop[randRow].geneBit[randCol] = (pop[randRow].geneBit[randCol] == '0') ? '1' : '0'; //1变为0, 0变为1 pop[randRow].fitValue = calcFitValue(binToDec(pop[randRow])); // 计算变异后的适应度值 #if (TEST==1) && (TEST_FLAG==4) //测试 printf("\n变异后,种群如下:\n"); test(pop); #endif }//end of mutation //更新种群 void updatePop(Chromosome *newPop, Chromosome *oldPop) { UINT i; for (i = 0; i < POP_NUM; i++) { oldPop[i] = newPop[i]; } }//end of updatePop //打印结果(当x为何值时,f(x)最大) void printResult(Chromosome *pop) { UINT i; UINT x = 0; UINT optValue = 0; // 函数的最优值 for (i = 0; i<POP_NUM; i++) { if (pop[i].fitValue > optValue) { optValue = pop[i].fitValue; x = binToDec(pop[i]); } } printf("\n当x=%d时,函数得到最大值为:%d\n\n", x, optValue); }//end of printResult //计算染色体的适应度值 UINT calcFitValue(UINT x) { return FUN_EXP(x); // }//end of calcFitValue //将类似二进制的基因位转化为十进制 UINT binToDec(Chromosome pop) { UINT i; UINT radix = 1; UINT result = 0; for (i = 0; i < GENE_NUM; i++) { //printf("%d", pop.geneBit[i]); result += (pop.geneBit[i] - '0')*radix; radix *= 2; } return result; }//end of binToDec void test(Chromosome *pop) { int i; int j; for (i = 0; i < POP_NUM; i++) { printf("%d: ", i + 1); for (j = 0; j < GENE_NUM; j++) printf("%c", pop[i].geneBit[j]); printf(" %4d", binToDec(pop[i])); printf(" fixValue=%d\n", calcFitValue(binToDec(pop[i]))); } }
相关文章推荐
- 算法设计与分析题目练习三:骑士旅游问题(回溯算法)
- 【算法设计与分析】6、最大字段和
- 算法分析与设计-10- 最大子段和的动态规划算法
- 算法设计与分析之-最大子段和 (分治)
- [算法设计与分析]4.1.1递推法(兔子繁殖+最大公约数3种方法)
- java实现算法设计与分析-最大间隙
- [算法设计与分析]3.4.2最大公约数的应用(循环移动数组元素)
- 算法分析与设计的一些题目
- 算法分析与设计实验——最大公约数
- 算法设计与分析不定期更新的日常之最大子段和四种方法
- 算法设计分析:相邻最大矩形面积
- 【算法设计与分析】最大子段和问题
- 高效算法设计_算法分析初步(最大连续和)
- Pku acm 2771 Guardian of Decency 数据结构题目解题报告(十五)---- 匈牙利算法求二分图的最大匹配
- 算法设计 最大网络流
- 算法设计分析中求最长公共子序列(C语言)
- 算法分析与设计实验
- 算法练习一:最大公约数与最小公倍数
- 动态规划;多边形游戏;类似圈型石头合并;算法设计分析作业;
- 蛙蛙推荐:算法练习:最大间隙问题