西电人工智能大作业(遗传算法求函数最大值)

西电人工智能大作业(遗传算法求函数最大值)

一、问题描述

在这里插入图片描述

二、算法分析

step1:确定种群规模N,交叉概率pc,变异概率pm。随机生成N个个体作为初始种群P。
step2:计算种群P中每个个体的适应度值。
step3:
1)从P中依据轮盘赌选择出N/2对父代;
2)对选择的N/2对父代,依概率pc进行交叉,生成的子代个体记为 P_s;
3)对集合O1中的个体依概率pm进行变异,生成的子代个体记为P_m;
4))从P、P_s、P_m中依据l轮盘赌选出N个个体组成下一代种群P。
step4:更新最大值,重复step2。

三、具体实现

1.种群编码实现

求maxf(x),其中x的取值范围是[a,b],精度要求不小于10^(-k),那么二进制位数m应该满足pow(2,m-1) - 1 < (b - a) < pow(2,m)
因此根据以上公式可以求出x1和x2的编码长度为len1 = 18,len2 = 15,总编码长度为len = 33。

#define x1min -3.0
#define x1max 12.1
#define x2min 4.1
#define x2max 5.8
#define len1 18
#define len2 15
#define len 33
typedef struct //个体结构体
{
   
   
	char code[len+1];
	double x1;
	double x2;
	double fitness;
	double fit_p;
	double fit_p_c;
}Individual;
//种群初始化
void InitPopu(Individual *P,int N)
{
   
   	
	int i,k,n;
	for(i = 0;i < N;i ++)
	{
   
   
		for(k = 0;k < len;k ++)
		{
   
   
			n = rand()%100;
			if(n<50)
				P[i].code[k] = '0';
			else
				P[i].code[k] = '1';
		}
		P[i].code[len] = '\0';
	}
}

2.种群解码实现

容易想到解码的方法可以采用比值的映射。
在这里插入图片描述

即:
(x - 0)/ (pow(2,m)-1-0) = (y - a) / (b - a)
所以y = a + (b - a) * x / (pow(2,m) - 1)
注意这里需要将二进制字符串转为十进制整型。
代码实现如下:

long long int binaryToDecimal(char *binaryString) 
{
   
   
    int i;
	long long int decimal = 0;
    int length = strlen(binaryString);
    for (i = 0; i < length; i++) 
        if (binaryString[i] == '1') 
            decimal += 1 << (length - i - 1);
    return decimal;
}
void decode(Individual *P,int N)
{
   
   
	int i,j;
	char code1[len1+1];
	char code2[len2+1];
	for(i = 0;i < N;i ++)
	{
   
   
		for(j = 0;j < len1;j ++)
			code1[j] = P[i].code[j];
		code1[len1] = '\0';
		for(j = 0;j < len2;j ++)
			code2[j] = P[i].code[j+len1];
		code2[len2] = '\0';
		long long int code1num = pow(2,len1);
		long long int code2num = pow(2,len2);
		long long int num1 = binaryToDecimal(code1);
		long long int num2 = binaryToDecimal(code2);
		P[i].x1 = x1min + (x1max - x1min) * num1 / (code1num - 1);
		P[i].x2 = x2min + (x2max - x2min) * num2 / (code2num - 1);
	}	
}

3.适应度计算实现

非常简单,直接上代码:

void CulFitness(Individual *P,int N)
{
   
   
	int i;
	for(i = 0;i < N;i ++)
		P[i].fitness = 21.5 + P[i].x1 * sin(4 * pi * P[i].x1) + P[i].x2 * sin(20 * pi * P[i].x2);
}

4.轮盘赌实现

思路:
为群体中每个个体指定饼图中一个小块。块的大小与个体的适应度成比例,适应度愈高,它在饼图中对应的小块所占面积也愈大。为了选取一个个体,要做的就是旋转这个轮子,直到轮盘停止时,看指针停止在
哪一块上,就选中与它对应的那个个体。
具体方案如图所示:
在这里插入图片描述
代码实现如下:

void Roulette(Individual *P,Individual *P_t,int N,int M)
{
   
   
	//计算P_t中N个个体适应度比值以及适应度比值前缀和
	int i,j;
	double sum = 0;
	for(i = 0;i < N;i ++)
	{
   
   
		sum += P_t[i].fitness;
		P_t[i].fit_p_c = sum;
	}	
	for(i = 0;i < N;i ++)
	{
   
   
		P_t[i].fit_p = P_t[i].fitness / sum;
		P_t[i].fit_p_c /= sum;
	}	
	double n;
	//从P_t中选出M个个体,存入P中
	for(i = 0;i < M;i ++)
	{
   
   
		n = (double)rand() / RAND_MAX;
		for(j = 0;j < N;j ++)
		{
   
   
			if(n<P[j].fit_p_c)
			{
   
   
				memcpy(&P[i],&P_t[j],sizeof(P[j]));
				break;
			}
		}
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值