版权声明:本文为博主原创文章,转载请注明出处。

先解释下什么是8皇后问题:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。在不考虑翻转和旋转等价的情况下,8皇后问题共有96个不同的解。

而n皇后问题就是将8*8的棋盘换为n*n的棋盘,同时摆放n个皇后使之不能相互攻击。

常用的解法是回溯法,通过不断递归的尝试来一个一个放置棋子,这种方法其实规避了很多不成立的情况,所以控制了一些解空间的范围,但是这种方法试图在一段程序当中将所有解求出来,随着n的变大,解空间在急速变大,递归的巨大空间开销会让求解变得很困难,效率会下降很多。

遗传算法也可以用来解决n皇后问题,但是遗传算法的本质是根据适应值来选择和制造更多的靠近目标情况的解,所以不一定能得到所有的解,同时也不能知道对于确定的n皇后问题的解的个数。在这种情况下的遗传算法有一些暴力破解的因素在其中。

下面谈一谈几个关键问题的解决(以8皇后问题为例)。

1、编码问题

我采用的是整数编码,染色体长度(基因位的个数)等于8,每一位为一个整数(该整数≥0,<8*8),且不能相同,每一个基因位表示的就是一个棋子摆放的位置。

2、适应值的计算问题

适应值的评价标准为发生冲突的个数n的倒数,即冲突越多,适应值越低,不发生冲突时适应值为1(1/1),但是这种评价也存在一定的问题,就是随着冲突的增多,适应值的减小会变的没那么明显(比如说不冲突适应值为1,冲突一个为0.5,冲突2个为0.333,冲突三个为0.25,冲突四个为0.2),所以选择的力度会相对较弱。可以考虑改为其他的方式进行评价。

3、选择问题

采用的是线性排名选择方式,因为上述原因,采用线性排名选择策略会一定程度上抵消掉适应值计算的问题。

4、突变问题

突变采用的是自适应性变异,即越收敛搜索范围越小的方法。

下面给出详细代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std; #define popSize 10000
#define maxGen 200
#define Pc 0.7
#define Pm 0.3
#define Pa 1.1
#define Pb 0.2
int chromSize=; class indivadual
{
public:
indivadual(){chrom.resize(chromSize);};
vector<int> chrom;
double fitness;
bool operator ==(const indivadual&i)
{
int t=;
for (t=;t<chromSize;t++)
{
if (find(chrom.begin(),chrom.end(),i.chrom[t])==chrom.end())
{
return false;
}
}
return true; }
}; class Evalution
{
private:
vector<indivadual> Population; indivadual Best;
int BestIndex;
indivadual Worst;
int WorstIndex;
indivadual HistoryBest;
double avg;
void Initialization();
void SelectPop();
void CrossPop();
void VaryPop();
void Optimizepop(){};
public:
Evalution();
void Evalute();
void NextPopulation();
void OutPut();
vector<indivadual> good;
int gen;
};
Evalution::Evalution()
{
Initialization();
}
void Evalution::Initialization()
{
int i=,j=;
Population.resize(popSize);
for (i=;i<popSize;i++)
{
j=;
while (j<chromSize)
{
int n=rand();
n=n%(chromSize*chromSize); if (find(Population[i].chrom.begin(),Population[i].chrom.end(),n)==Population[i].chrom.end()||n==)
{
Population[i].chrom[j]=n;
j++;
}
} //发的
}
Worst=Best=Population[];
WorstIndex=BestIndex=;
gen=;
avg=;
Best.fitness=;
Worst.fitness=;
} void Evalution::Evalute()
{
int index=;
for (index=;index<popSize;index++)
{
//适应值最大为1
Population[index].fitness=;
//横坐标
vector<int> x;
x.resize(chromSize);
//纵坐标
vector<int> y;
y.resize(chromSize);
int i=,j=,q=,p=;
for (j=;j<chromSize;j++)
{
p=Population[index].chrom[j]/chromSize;
x[j]=p;
q=Population[index].chrom[j]%chromSize;
y[j]=q;
}
for (i=;i<chromSize;i++)
{
for (j=i+;j<chromSize;j++)
{
if (x[i]==x[j])
{
Population[index].fitness++;
}
}
}
for (i=;i<chromSize;i++)
{
for (j=i+;j<chromSize;j++)
{
if (y[i]==y[j])
{
Population[index].fitness++;
}
}
}
//取交叉数目的倒数为适应值
Population[index].fitness=/Population[index].fitness;
if (Population[index].fitness==&&find(good.begin(),good.end(),Population[index])==good.end())
{
good.push_back(Population[index]);
}
//更新当代最佳
if (Best.fitness<Population[i].fitness)
{
Best=Population[index];
BestIndex=index;
}
//更新当代最差
if (Worst.fitness>Population[index].fitness)
{
Worst=Population[index];
WorstIndex=index;
}
}
//更新历史最佳
if (HistoryBest.fitness<Best.fitness)
{
HistoryBest=Best;
}
//计算平均值
for (index=;index<popSize;index++)
{
avg+=Population[index].fitness;
}
avg/=popSize;
//代数更替
gen++; }
void Evalution::NextPopulation()
{
//选择
SelectPop();
//交叉
CrossPop();
//变异
VaryPop();
//评价
Evalute();
//优化
Optimizepop();
} //输出
void Evalution::OutPut()
{ cout<<"当前代数"<<gen<<" 平均值"<<avg<<" 最好个体适应值"<<Best.fitness<<"最好个体基因";
int i=;
for (i=;i<chromSize;i++)
{
cout<<Best.chrom[i]<<" ";
}
cout<<endl;
} //sort函数的辅助函数
bool compare(indivadual a,indivadual b)
{
if (a.fitness>b.fitness)
{
return true;
}
if (a.fitness>b.fitness)
{
return false;
}
return false;
} //线性排名选择
void Evalution::SelectPop()
{
sort(Population.begin(),Population.end(),compare);
double p[popSize],selection[popSize];
indivadual newPopulation[popSize];
double FitSum=;
int i=,j=,index=,popindex=;
//计算分配概率
for (i=;i<popSize;i++)
{
j=i+;
p[i]=(Pa-Pb/(j+))/j;
}
//求分配概率的总和
for(index=;index<popSize;index++)
{
FitSum+=p[index];
} //确定轮盘分布
for(index=;index<popSize;index++)
{
selection[index]=p[index]/FitSum;
}
for(index=;index<popSize;index++)
{
selection[index]=selection[index]+selection[index-];
}
//用轮盘进行随机选取,形成新的种群
for(popindex=;popindex<popSize;popindex++)
{
double n= (rand()%)/100.0;
index=;
while(n>selection[index])
index++;
newPopulation[popindex]=Population[index];
}
//将刚产生的群体替换为系统的群体
for(index=;index<popSize;index++)
{
Population[index]=newPopulation[index];
}
} //杂交算子,离散杂交
void Evalution::CrossPop()
{
int index=,position=,i=,temp=,t=;
for(;index<popSize;index++)
{
indivadual temp;
int r=rand()%popSize;
temp=Population[index];
Population[index]=Population[r];
Population[r]=temp;
}
for(index=;index<popSize;index+=)
{
t=rand()%/1000.0;
if (t<Pc)
{
position=rand()%chromSize;
for (i=position+;i<chromSize;i++)
{
temp=Population[index+].chrom[i];
Population[index+].chrom[i]=Population[index].chrom[i];
Population[index].chrom[i]=temp; } } }
} //变异算子,自适应性变异
void Evalution::VaryPop()
{
int i=,j=,up=chromSize*chromSize-,down=;
for (i=;i<popSize;i++)
{
for (j=;j<chromSize;j++)
{
double r=rand()%/1000.0;
if (r<Pm)
{
double t=-Population[i].fitness*0.9999/Best.fitness;
//突变区间
int u=(-pow(r,pow(t,)))*(up-Population[i].chrom[j]); if (u>up)
{
u=up;
}
if (u<down)
{
u=down;
}
int l=(-pow(r,pow(t,)))*(Population[i].chrom[j]-down);
if (l>up)
{
l=up;
}
if (l<down)
{
l=down;
} int p=rand()%;
if (p==)
{
Population[i].chrom[j]=u;
}
else
Population[i].chrom[j]=l;
}
}
}
} int main()
{
cout<<"n=";
int n=;
cin>>n;
chromSize=n;
Evalution eva;
eva.Evalute();
eva.OutPut();
while(eva.gen<maxGen)
{
eva.NextPopulation();
eva.OutPut();
}
int i=,j=;
cout<<"解共有"<<eva.good.size()<<endl;
for (i=;i<eva.good.size();i++)
{
for (j=;j<chromSize;j++)
{
cout<<eva.good[i].chrom[j]<<" ";
}
cout<<endl; }
}

特别要注意的是变异参数的Pm的值需要调的相对较大,因为需要搜索更大的空间范围。

种群个数10000,最大代数为100

种群个数10000,最大代数200

种群个数20000,最大代数100

种群个数20000,最大代数200

自己写的这个问题还是比较大,从结果上看要大规模长时间的计算才能计算出部分解,也和算法本身有关,其实也和算法设计中缺乏剪枝操作,没有删去一些显而易见的错误解,导致计算时间过长,同时浪费了部分空间。留待日后改正吧。

简单遗传算法求解n皇后问题的更多相关文章

  1. 遗传算法:N皇后

    N皇后问题描述 N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行.同一列.同一斜线上的皇后都会自动攻击). 遗传算法 遗传算法是局部束搜索的变形: 与自 ...

  2. USACO 1.5.4 Checker Challenge跳棋的挑战(回溯法求解N皇后问题+八皇后问题说明)

    Description 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行,每列,每条对角线(包括两条主对角线的所有对角线)上都至多有一个棋子. 列号 0 1 2 3 4 5 6 ...

  3. 数据结构学习之栈求解n皇后问题

    数据结构学习之栈求解n皇后问题 0x1 目的 ​ 深入掌握栈应用的算法和设计 0x2 内容 ​ 编写一个程序exp3-8.cpp求解n皇后问题. 0x3 问题描述 即在n×n的方格棋盘上,放置n个皇后 ...

  4. 利用遗传算法求解TSP问题

    转载地址 https://blog.csdn.net/greedystar/article/details/80343841 目录 一.问题描述 二.算法描述 三.求解说明 四.参考资料 五.源代码 ...

  5. kb-01-a<简单搜索--dfs八皇后问题变种>

    题目描述: 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的 ...

  6. 回溯法求解n皇后和迷宫问题

    回溯法是一种搜索算法,从某一起点出发按一定规则探索,当试探不符合条件时则返回上一步重新探索,直到搜索出所求的路径. 回溯法所求的解可以看做解向量(n皇后坐标组成的向量,迷宫路径点组成的向量等),所有解 ...

  7. 回溯法——求解N皇后问题

    问题描写叙述 八皇后问题是十九世纪著名数学家高斯于1850年提出的.问题是:在8*8的棋盘上摆放8个皇后.使其不能互相攻击,即随意的两个皇后不能处在允许行.同一列,或允许斜线上. 能够把八皇后问题拓展 ...

  8. 求解n皇后

    要求:在国际象棋上摆放n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法 思路:很直观的想法就是在棋盘上一个一个皇后的摆,如果冲突,则摆放在另一个位置,直至 ...

  9. CSharp遗传算法求解背包问题

    断断续续写了四天,感觉背包问题是最适合了解遗传算法的问题模型 using System; using System.Collections.Generic; using System.Linq; us ...

随机推荐

  1. 精通Linux的“kill”命令

    无论你使用哪种操作系统,你一定会遇到某个行为失常的应用,它把自己锁死并拒绝关闭.在Linux(还有Mac),你可以用一个"kill"命令强制终结它.在这个教程中,我们将展示给你多种 ...

  2. TMS320F2803x系列实时控制 MCU 技术文档

      C2000系列实时控制器简介: C2000 生产选择指南 sprufk8.pdf 数据表: 中文板:TMS320F28030/28031/28032/28033/28034/28035 Picco ...

  3. Contest 7.21(贪心专练)

    这一次都主要是贪心练习 练习地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=26733#overview Problem APOJ 13 ...

  4. hash_map vs unordered_map vs map vs unordered_set

    hash_map vs unordered_map 这两个的内部结构都是采用哈希表来实现.unordered_map在C++11的时候被引入标准库了,而hash_map没有,所以建议还是使用unord ...

  5. IoC/DI

    From:http://jinnianshilongnian.iteye.com/blog/1471944 我对IoC/DI的理解 博客分类: spring杂谈 IoCDI  IoC IoC: Inv ...

  6. PostgreSQL的 initdb 源代码分析之二

    继续分析 下面这一段,当 initdb --version 或者  initdb --help 才有意义. ) { ], || strcmp(argv[], ) { usage(progname); ...

  7. ural 1998 The old Padawan

    先预处理每一个点往前退几步 就一个trick..要处理这一秒已经超出了要拿完所花的时间 #include <iostream> #include <cstring> #incl ...

  8. MySQL 子查询 EXISTS 和 NOT EXISTS(转)

    MySQL EXISTS 和 NOT EXISTS 子查询 MySQL EXISTS 和 NOT EXISTS 子查询语法如下: SELECT ... FROM table WHERE EXISTS ...

  9. SVN Cleanup failed的解决办法

    一开始没有更新执行了提交操作,提示有冲突 再执行更新操作的时候出现了“之前操作未完成,如果该操作被中断了执行cleanup命令”的提示

  10. 使用mii-tool设置网卡速率

    转载:http://washion2008.blog.163.com/blog/static/144227201001711537158/ 在ubuntu中,mii-tool 是属于net-tools ...