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

先解释下什么是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. Simple guide to Java Message Service (JMS) using ActiveMQ

    JMS let’s you send messages containing for example a String, array of bytes or a serializable Java o ...

  2. Hibernate HQL和原生SQL查询的一点区别

    1.createSQLQuery 1.1默认查询的结果为BigDecimal 1.2通过addScalar("CGD_ID", StandardBasicTypes.LONG)可以 ...

  3. Unity3D之空间转换学习笔记(一):场景物体变换

    该系列笔记基于Unity3D 5.x的版本学习,部分API使用和4.x不一致. 目前在Unity3D中,除了新的UGUI部分控件外,所有的物体(GameObject)都必带有Transform组件,而 ...

  4. c# 递归算法

    c# 递归算法 2009-03-13 09:44 6950人阅读 评论(8) 收藏 举报 算法c#funn2c 1)1.1.2.3.5.8.......用递归算法求第30位数的值? 首先我们可以发现从 ...

  5. 自己学会汉化DevExpress控件[转]

    1. 文档导读 本文档以颜色区分内容的重要性和不同性,阅读本文档时请注意以下事项: 1. 红色部分表示需要注意的重点内容:(加粗的尤甚) 2. 蓝色部分表示相应于前版本新增的内容: 3. 紫色部分表示 ...

  6. Linux在向磁盘新建文件的时候在系统层面的四步操作

    ----------- 1.存储文件属性.内核先找到一个空的i节点,并把文件属性信息记录其中.   2.存储数据.先计算要多少个磁盘块,在内核自由块列表找到合适数量的磁盘块,并把数据从内核的缓冲区依次 ...

  7. Codeforces Round #185 (Div. 2) A. Whose sentence is it? 水题

    A. Whose sentence is it? Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/ ...

  8. Codeforces Gym 100286G Giant Screen 水题

    Problem G.Giant ScreenTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/con ...

  9. C#获得和发送网站Session

    request = (HttpWebRequest)WebRequest.Create(url);                                         if (Const. ...

  10. 第八讲:HTML5中canvas实现小球击打小方块游戏

    源码:http://download.csdn.net/detail/liumingm900913/7469969 游戏开发流程: 1.创建画布: 将画布放在div标签里面,这样能够控制画布居中的位置 ...