A.I. 求 函数F(x)= xsin(10π*x) + 2.0,x∈ [-1,2]的最大值问题

遗传算法好像好蛮好玩的。但是跑的太慢了,还有很多优化的地方,只是给一个poor版

/*问题:
1.怎么编码呢? 已经说了是22位,那么编码后的值区间是[0,2^22-1]x1 而实际取值在[-1,2]x
所以换算公式是 解码公式得到,编码也差不多了。
其他的就没什么了。
[*/
#include<iostream>
#include<cstdio>
#include<cmath>
#include <string>
#include<vector>
#include <ctime>
#include<cstring>
#define eps 1e-6 
#define Pi acos(-1)
const int SIZE = 50;
const int Len = 22;
const int Val = 4194304;
const int Times = 1e2;
using namespace std;
/*------------------------------------------编码------------------------------------------*/
string Encode(double x) {/*(1+x)*(4194303)/3=x1 2^22=4194304*/
	string ans = "";
	int tmp = (1 + x) * (Val - 1) / 3.0 + 0.5;//四舍五入
	int Binpow = Val / 2;
	while (Binpow >= 1) {
		if (tmp >= Binpow) {
			ans += '1';	tmp -= Binpow;
		}
		else ans += '0';
		Binpow >>= 1;
	}
	return ans;
}
double Decode(string s) {/* 3/(2^22-1)*x1 - 1 = x。*/
	int ans = 0;
	for (int i = 0;i < 22;++i)
		ans = (ans << 1) + s[i] - '0';
	return 3.0 * (ans) / (Val - 1) - 1.0;
}
/*----------------------------------------------------------------------------------------*/
/*--------------------------------------产生初始种群--------------------------------------*/
vector<string>Species;
void Init() {//初始化,生成22位的基因码
	for (int i = 0;i < 50;++i) {
		string s = "";
		for (int j = 0;j < Len;++j)
			s += rand() % 2 + '0';
		Species.push_back(s);
	}
}
/*----------------------------------------------------------------------------------------*/
/*---------------------------------------计算适应度---------------------------------------*/
double fitness[SIZE+5] = { 0 };//第50个放总适应度,方便选择。
double Max_fitness = 0;//最大的咱们先无条件保留吧。为啥?任性,我的代码我做主。这也是最后的答案。
int index = 0;
double Function(double x) { return x * sin(10.0 * Pi * x) + 2.0; }
void CalcuFitness() {//记算适应度
	memset(fitness, 0, sizeof(fitness));
	for (int i = 0;i < SIZE;++i) {
		fitness[i] = Function(Decode(Species[i]));
		fitness[50] += fitness[i];
		if (fitness[i] > Max_fitness) { Max_fitness = fitness[i]; index = i; }
	}
}
/*----------------------------------------------------------------------------------------*/
/*------------------------------------------选择------------------------------------------*/
int Select() {//先爹后妈
	double proportion = 1.0 * rand() / RAND_MAX;//生成从0到1的浮点数
	int i = rand() % SIZE;//随机起点,避免每次都从头检索。
	for (int j = i - 1;i < SIZE && j >= 0;++i, --j) {//以i为起点向两边遍历
		if (i<SIZE && fitness[i] * 1.0 / fitness[50] > proportion) return i;
		if (j >= 0 && fitness[j] * 1.0 / fitness[50] > proportion) return j;
	}
	return Select();//没得选,那就接着选
}
/*----------------------------------------------------------------------------------------*/
/*----------------------------------------遗传操作----------------------------------------*/
vector<string>Offspring;//后代勒。
int Rand() { return rand() % SIZE; }
void Born() {//生娃
	Offspring.push_back(Encode(Max_fitness));//让这个最杰出的活久一点。
	int mother, father, pos, cnt;
	while (Offspring.size() < SIZE) {
		mother = Select(), father = Select();//找父母
		double tmp1 = fitness[mother], tmp2 = fitness[father];
		if (mother == father) continue;//放过自己吧
		cnt = Rand() % 4;//别交叉太多,不然不像亲生的。0,1,2,3
		while (cnt-- > 0) {//交叉
			pos = Rand() % Len;
			swap(Species[mother][pos], Species[father][pos]);
		}
		if(Function(Decode(Species[mother]))>fitness[mother])//选比双亲强的
		Offspring.push_back(Species[mother]);
		if (Function(Decode(Species[father])) > fitness[father])
		Offspring.push_back(Species[father]);
	}
	if(Offspring.size()>50)
	Offspring.pop_back();//很明显两个两个一加,可能会变成51个,那么要去掉一个。
}

/*----------------------------------------------------------------------------------------*/
/*----------------------------------------变异操作----------------------------------------*/
void Vary() {
	int pos = Rand() % Len, cnt = Rand() % 6, index = Rand();
	while (cnt-- > 0)//挑几次几个后代几个点变异。
		Offspring[index][pos] = (Offspring[index][pos] - '0') ? '0' : '1';
	Species.assign(Offspring.begin(), Offspring.end());//孩子变成大人
}
/*----------------------------------------------------------------------------------------*/
inline void GA() {//一次遗传算法
	CalcuFitness();
	Born();
	Vary();
}
int main() {
	//cout << Decode(Encode(0.637197)) << endl;
	/*double start = clock();
	double Max = 0,tmp;
	for (double x = -1.0;x <= 2.0;x += eps) {
		tmp = Function(x);
		if (tmp > Max) Max = tmp;
	}
	double end = clock();
	printf("%.6lf\n", Max);
	printf("Time spent: %lfms\n", 1000.0 * (end - start) / CLOCKS_PER_SEC);
	暴力得到 最大值 Max=3.850274,花费1753ms*/
	srand((unsigned)time(NULL));
	double start = clock();
	Init();
	for (int i = 1;i <= Times;++i)
		GA();
	double end = clock();
	printf("当x=%.6lf,f(x)=%.6lf,x的二进制=%s\n",Decode(Species[index]), Max_fitness,Species[index].c_str());
	printf("Times=%d次,Time spent: %lfs\n",Times,1.0*(end - start) / CLOCKS_PER_SEC);
	return 0;
}
/*----------------------------------------------------------------------------------------
	Tiny Genetic Algorithm
------------------------------------------------------------------------------------------*/


  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值