八皇后问题遗传算法c语言,遗传算法解决八皇后问题

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

八皇后问题描述

19 世纪著名的数学家 Gauss 在 1850 年提出八皇后问题后, 该问题成为各类语言程序设计的经典题目。 八皇后问题要求在 8×8 格的国际象棋上摆放八个皇后,使横、竖、斜方向上都不能有两个及两个以上皇后在同一条直线上, 问题也可以推广到 N 个皇后。 穷举法在问题规模不大的情况

下还可适用,回溯法是求解此问题的经典算法。但N 皇后问题是个 NP 难问题, 随着皇后数目的增多, 求解复杂度激增, 就需利用非常规的技术求

解。 遗传算法在求解一些 NP 完全问题上得到了广泛地应用,本文用遗传算法求解八皇后问题,给出详细的实现过程。

基本遗传算法求解过程

基本遗传以初始种群为基点, 经过选择、交叉、变异操作生成新的种群,如此更新种群直到满足终止条件。 其计算步骤如下:(1) 将问题空间转换为遗传空间, 也就是编码;

(2)随机生成 P 个染色体作为初始种群;

(3)染色体评价,也就是按确定的适应度函数计算各个染色体的适应度;

(4)根据染色体适应度,按选择算子进行染色体的选择;

(5)按交叉概率进行交叉操作;

(6)按变异概率进行变异操作;

(7)返回(4)形成新的种群,继续迭代,直到满足终止条件。

基本遗传算法给出了基本框架, 针对求解的问题不同, 遗传算法在相应的计算步骤中有不同的设计。 本文针对八皇后问题, 设计了相应的编码,适应度计算方法,交叉和变异操作。

实现过程和主要代码

随机生成4个长度为8位的种群放入vector >p容器,设置变异率0.6,进行迭代。迭代出的后代若适应度前代比前代好,则更新种群,否则放弃。

设置种群和变异率

void MainWindow::calc()

{

loc.resize(0);

srand((unsigned)time(NULL));

vector > p(gen.pSize);

for(int num = 0;num < gen.pSize;num++) {

p[num] = gen.random_initial_state();

}

//将种群p已经变异率0.6进行迭代

if (gen.genetic_algorithn(p, 0.6) == 1) {

int i=0,j=0;

for(i = 0;i<8;i++) {

point.resize(0);

point.push_back(++j);

point.push_back(gen.state[i]+1);

loc.push_back(point);

}

//更新棋盘

MainWindow::update();

}

}

遗传算法

// 遗传算法

bool Genetic::genetic_algorithn(vector > &p, float mutateRate)

{

vector > old_p = p;

vector > new_p(p.size());

// 遗传代数设置为 10000 代

for (int n = 0; n < 10000; ++n) {

for (unsigned int i = 0; i < p.size(); ++i) {

// 挑选参与繁殖的两个个体

vector x = random_selection(old_p);

vector y = random_selection(old_p);

// 产生后代

vector child = reproduce(x, y);

// 后代变异

mutate(child, mutateRate);

new_p[i] = child;

if(fitness(child) == 0) {

for(int ii=0;ii

state[ii] = child[ii];

}

return 1;

}

}

old_p = new_p;

}

return false;

}

根据适应度选择种群

// 用于挑选种群 p 中参与繁殖的个体,适应度函数评价越高的个体越容易被挑选

vector Genetic::random_selection(vector > &p)

{

#if 1

vector temp;

temp.resize(pSize);

int total=0;

float probability[pSize] = { 0 };

for(int i = 0;i < pSize;i++) {

temp[i] = 28 - fitness(p[i]);

total+=temp[i];

}

for(int i = 0;i < pSize;i++) {

probability[i] = (float)(temp[i] / total);

}

float r = (float)rand() / RAND_MAX;

for(int i = 0;i < pSize;i++) {

static float a = 0;

a += probability[i];

if (r

return p[i];

}

#endif

#if 0

vector temp;

temp.resize(pSize);

for(int i = 0;i < pSize;i++) {

temp[i] = fitness(p[i]);

}

auto smallest = std::min_element(std::begin(temp), std::end(temp));

int postion = std::distance(std::begin(temp), smallest);

return p[postion];

#endif

return p[rand()%pSize];

}

染色体交叉

// 杂交产生后代,给定参与配对的父母状态 x 和 y

vector Genetic::reproduce(vector x, vector y)

{

// 确保杂交点不是第一个数字之前和最后一个数字之后,也即后代一定包括了父母双方的信息

int cut = rand() % 7;// 0 1 2 3 4 5 6

cut++;// 1 2 3 4 5 6 7

vector ans;

for(int i = 0;i

ans.push_back(x[i]);

}

for(unsigned int i = cut;i

ans.push_back(y[i]);

}

return ans;

}

染色体变异

// 变异,给定的个体状态 s 以 rate 的几率发生变异

bool Genetic::mutate(vector &s, float rate)

{

vector new_s = s;

if ( ((float)rand() / RAND_MAX ) <= rate) {

new_s[rand()%8] = rand()%8;

if (fitness(new_s) <= fitness(s)) {

s = new_s;

}

}

return false;

}

适应度函数

//适应度判断,不在同一条直线和对角线上

int Genetic::fitness(vector s)

{

int value = 0;

for(int i = 0;i

for(int j = i+1;j

if (s[i] == s[j]) {

value++;

}

if (abs(i - j) == abs(s[i] - s[j])) {

value++;

}

}

}

return value;

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值