zoukankan      html  css  js  c++  java
  • 遗传算法解决函数优化问题

    一、实验目的

    1.掌握遗传算法的基本原理和步骤。

    2. 复习VB、VC的基本概念、基本语法和编程方法,并熟练使用VB或VC编写遗传算法程序。

    二、实验内容

    1. 上机编写程序,解决以下函数优化问题:

    2. 调试程序。

    3. 根据实验结果,撰写实验报告。

    三、实验原理

    遗传算法是一类随机优化算法,但它不是简单的随机比较搜索,而是通过对染色体的评价和对染色体中基因的作用,有效地利用已有信息来指导搜索有希望改善优化质量的状态。

    标准遗传算法流程图如下图所示,主要步骤可描述如下:

    ① 随机产生一组初始个体构成初始种群。

    ② 计算每一个体的适配值(fitness value,也称为适应度)。适应度值是对染色体(个体)进行评价的一种指标,是GA进行优化所用的主要信息,它与个体的目标值存在一种对应关系。

    ③ 判断算法收敛准则是否满足,若满足,则输出搜索结果;否则执行以下步骤。

    ④ 根据适应度值大小以一定方式执行复制操作(也称为选择操作)。

    ⑤ 按交叉概率pc执行交叉操作。

    ⑥ 按变异概率pm执行变异操作。

    ⑦ 返回步骤②。

    图1.1 标准遗传算法流程图




    代码实现::::::

    #include <stdio.h>
    #include <math.h>
    #include <stdlib.h>
    #include<time.h>
    
    #define byte unsigned char
    #define step 200 //步长
    #define MAX 50	
    #define N 10 //随机数个数
    #define Pc 0.74  //被选择到下一代的概率,个数=Pc*N,小于N   下一代数=上一代,不用处理
    #define Pt 0.25  //交叉的概率,个数=Pt*N 舍,小于N    0~(n2+1)随机数,之后部分开始交叉
    #define Pm 0.01  //变异的概率,个数=Pm*N*n2 入,小于N    0~(N*(n2+1))随机数/(n2+1)=个体,0~(N*(n2+1))随机数%(n2+1)=该个体基因位置
    #define n2 15//2的15次方,共16位
    #define next_t (int)(Pt*N)//交叉个数
    #define next_m (int)(Pm*N+1)//变异个数  向后约等于
    #define e 0.001//次数限制阈值
    /*
    int N=10; //随机数个数
    float Pc=0.74;  //被选择到下一代的概率,个数=Pc*N,小于N   下一代数=上一代,不用处理
    float Pt=0.25;  //交叉的概率,个数=Pt*N 舍,小于N    0~(n2+1)随机数,之后部分开始交叉
    float Pm=0.01;  //变异的概率,个数=Pm*N*n2 入,小于N    0~(N*(n2+1))随机数/(n2+1)=个体,0~(N*(n2+1))随机数%(n2+1)=该个体基因位置
    */
    byte  bitary[N][n2+1],bitary0[N][n2+1];//二进制
    int src1[N];
    
    float ShowType(int a);//表现型
    void BinNum(int a);//二进制位数n2
    float fit_func(float a);//适应度
    void DecToBin (int src,int num);//十进制转二进制
    void BinToDec (void);//十进制转二进制
    int selectT(float a,float b[10]);//选择交叉个体
    int selectM(float a,float b[10]);//选择变异个体
    
    void main(void)
    {
        //范围是[-100,100]***************************
    	int   src[N],i=0,j=0,k=0,count=0;//十进制
    	float show[N];//表现型
    	float fit[N],sumfit=0;//适应度
    	float pcopy[N];//优胜劣汰,遗传到下一代的概率fit[i]/总和(fit[i])
    	float pacc[N];//pcopy[i]累加概率值
    	float prand[N];//随机产生N个0~1的下一代概率
    	int iselect;//根据概率选择到的个体序号
    	int new_select[N];//根据概率选择到的个体
    	int new_T[next_t],new_M[next_m];
    	float min,min1;
    
    	printf("随机数(原始母体),表现型, 适配值\n");
    	srand( (unsigned)time(NULL) );
    	for(i=0;i<N;i++)
    	{	
    		src[i]=rand()%32768; //rand()%201-100===>-100~100的十进制随机数	随时间递增 
    		show[i]=ShowType(src[i]);//转化成表现型
    		
    		fit[i]=fit_func(show[i]);//计算各个适配值(适应度)
    		sumfit=sumfit+fit[i];  //种群的适应度总和
    		printf("%5d,  %f,  %f\n",src[i],show[i],fit[i]);
    
    	}
    	printf("\n第%d代适配总值\n%f\n",count,sumfit);//第0代
    	count++;	
    	min=sumfit;
    
    	printf("\n遗传到下一代的概率\n");
    	for(i=0;i<N;i++)
    	{
    		pcopy[i]=fit[i]/sumfit;
    		printf("%f, ",pcopy[i]);
    	}
    // 求选择(被复制)的累加概率,用于轮盘赌产生随机数区域,选择下一代个体	
    	printf("\n遗传到下一代的累加概率\n");
    	pacc[0]=pcopy[0];
    	for(i=1;i<N;i++)
    	{
    		pacc[i]=pacc[i-1]+pcopy[i];
    		printf("%f, ",pacc[i]);
    	}
    
    //每个src[N]都随机取其中一个pcopy,取得的值pcopy[i]跟pcopy概率大小有关
    //模拟轮盘赌方式选择新一代
    	printf("\n\n新产生的第%d代,表现型, 适配值\n",count);
    	srand( (unsigned)time(NULL) );
    	for(i=0;i<N;i++)
    	{	
    		prand[i]=(float)( (rand()%101)*0.01 );//0~1的十进制小数 ,精确到0.01
    		iselect=selectT(prand[i],pacc);
    		new_select[i]=src[iselect];//产生的新一代,十进制
    		show[i]=ShowType(new_select[i]);//转化成表现型
    		fit[i]=fit_func(show[i]);
    		DecToBin (new_select[i],i);
    		sumfit=sumfit+fit[i];  //种群的适应度总和
    		printf(" %d  %f   %f\n",new_select[i],show[i],fit[i]);
    	}
    	printf("\n第%d代适配总值\n%f\n",count,sumfit);//第1代
    	min1=sumfit;
    	if (min>sumfit)
    	{
    		min1=min;
    		min=sumfit;
    	}
    	
    	while(fabs(min-min1)>e&&count<MAX)
    	{
    		//从新一代选择个体交叉
    		printf("\n随机产生交叉个体号   ");
    		srand( (unsigned)time(NULL) );
    
    		for(i=0;i<2;i++)    //简单起见交叉数设为2
    		{	
    			new_T[i]=rand()%N;//0~10的十进制数	产生的交叉个体
    			if (i>0)//两个不同个体交叉
    			while(new_T[i]==new_T[i-1])
    				  new_T[i]=rand()%N;	
    			printf("%d,  ",new_T[i]);
    		}
    
    		srand( (unsigned)time(NULL) );//随机产生交叉位置
    		k=rand()%n2;//0~14的十进制数	
    		printf("\n随机产生交叉位置   %d\n",k);	
    		printf("\n原编码\n");	
    		for(j=n2;j>=0;j--)
    		printf("%c",bitary[new_T[0]][j]);
    		printf("\n");	
    		for(j=n2;j>=0;j--)
    		printf("%c",bitary[new_T[1]][j]);
    		printf("\n位置%d后交叉编码\n",k);
    		char temp;
    		for(i=k+1;i<n2+1;i++)//交叉
    		{	
    			temp=bitary[new_T[0]][i];
    			bitary[new_T[0]][i]=bitary[new_T[1]][i];
    			bitary[new_T[1]][i]=temp;
    		}
    		for(j=n2;j>=0;j--)
    			printf("%c",bitary[new_T[0]][j]);
    			printf("\n");	
    		for(j=n2;j>=0;j--)
    			printf("%c",bitary[new_T[1]][j]);
    		//从新一代选择个体变异
    		printf("\n随机产生变异个体号  ");
    		srand( (unsigned)time(NULL) );
    		for(i=0;i<1;i++)  //简单起见变异数设为1个
    		{	
    			new_M[i]=rand()%N;//0~9的十进制数	产生的变异个体
    			k=rand()%(n2+1);//0~15的十进制数
    			printf("%d\n编码位置  %d\n原编码\n",new_M[i],k);
    			for(j=n2;j>=0;j--)
    				printf("%c",bitary[new_M[i]][j]);
    			if (bitary[new_M[i]][k]=='0')//变异取反
    					bitary[new_M[i]][k]='1';
    			else bitary[new_M[i]][k]='0';
    				printf("\n位置%d变异后编码\n",k);
    			for(j=n2;j>=0;j--)
    				printf("%c",bitary[new_M[i]][j]);				
    		}
    		printf("\n");
    		count++;
    		//新的bitary即产生第二代
    		printf("\n新产生的第%d代\n",count);
    		for(i=0;i<N;i++)
    		{
    			for(j=n2;j>=0;j--)
    			printf("%c",bitary[i][j]);
    			printf("\n");
    		}
    		BinToDec ();//二进制转十进制
            for(i=0;i<N;i++)
    		{	
    			new_select[i]=src1[i];
    			show[i]=ShowType(src[i]);//转化成表现型
    			fit[i]=fit_func(show[i]);//计算各个适配值(适应度)
    			sumfit=sumfit+fit[i];  //种群的适应度总和
    			printf("%5d,  %f,  %f\n",src1[i],show[i],fit[i]);
    		}
    		printf("\n第%d代适配总值\n%f\n",count,sumfit);
    		if (sumfit<min)
    		{
    			min1=min;
    			min=sumfit;
    		}
    	}
      printf("\n\n\n*****************\n    over   \n*****************\n",sumfit);
    }
    
    
    //////////////////////////子函数////////////////
    float ShowType(int a)
    {
    	float temp;
    	temp=(float)(a*200.0/32767-100);//(2的15次方减1)=32767
    	return temp;
    }
    
    float fit_func(float a)
    {
    	float temp;
    	temp=a*a;
    	return temp;
    }
    
    void DecToBin (int src,int num)
    {
    	int i;
    	//注意负数的补码
    	if (src<0)
    	{
    		src=(int)pow(2,16)-abs(src);
    	}
    	for (i=0;i<=n2;i++)
    	{
    		bitary[num][i]='0';
    		bitary0[num][i]='0';
    		if(src)
    		{
    			bitary[num][i]=(src%2)+48;
    			bitary0[num][i]=(src%2)+48;
    			src=(int)(src/2);
    		}
    	}
    }
    
    void BinToDec (void)
    {
    	int i,j;
    	for(i=0;i<N;i++)
    	{
    		src1[i]=0;
    		for(j=0;j<n2+1;j++)
    		{
    			src1[i]=src1[i]+(bitary[i][j]-48)*(int)pow(2,j);	
    		}
    	}
    }
    
    int selectT(float a,float b[10])
    {
    	int i;
    	for(i=0;i<N;i++)
    	{
    		if (a<b[i])
    			return i;
    	}
    	return -1;
    }


  • 相关阅读:
    创业第一步:为员工打工
    C#笔记30:Trace、Debug和TraceSource的使用以及日志设计
    C#笔记29:程序集、应用程序配置及App.config和YourSoft.exe.config
    WPF快速指导1:资源
    并行编程之数据并行
    异常处理之ThreadException、unhandledException及多线程异常处理
    Efficient C#:为什么要把泛型作为返回值
    C#笔记31:本地化或多语言支持
    C#数据本地存储方案之SQLite
    C#笔记9:异常
  • 原文地址:https://www.cnblogs.com/zhujinghui/p/3369247.html
Copyright © 2011-2022 走看看