简单遗传算法求解n皇后问题
版权声明:本文为博主原创文章,转载请注明出处。
先解释下什么是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皇后问题的更多相关文章
- 遗传算法:N皇后
N皇后问题描述 N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行.同一列.同一斜线上的皇后都会自动攻击). 遗传算法 遗传算法是局部束搜索的变形: 与自 ...
- USACO 1.5.4 Checker Challenge跳棋的挑战(回溯法求解N皇后问题+八皇后问题说明)
Description 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行,每列,每条对角线(包括两条主对角线的所有对角线)上都至多有一个棋子. 列号 0 1 2 3 4 5 6 ...
- 数据结构学习之栈求解n皇后问题
数据结构学习之栈求解n皇后问题 0x1 目的 深入掌握栈应用的算法和设计 0x2 内容 编写一个程序exp3-8.cpp求解n皇后问题. 0x3 问题描述 即在n×n的方格棋盘上,放置n个皇后 ...
- 利用遗传算法求解TSP问题
转载地址 https://blog.csdn.net/greedystar/article/details/80343841 目录 一.问题描述 二.算法描述 三.求解说明 四.参考资料 五.源代码 ...
- kb-01-a<简单搜索--dfs八皇后问题变种>
题目描述: 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的 ...
- 回溯法求解n皇后和迷宫问题
回溯法是一种搜索算法,从某一起点出发按一定规则探索,当试探不符合条件时则返回上一步重新探索,直到搜索出所求的路径. 回溯法所求的解可以看做解向量(n皇后坐标组成的向量,迷宫路径点组成的向量等),所有解 ...
- 回溯法——求解N皇后问题
问题描写叙述 八皇后问题是十九世纪著名数学家高斯于1850年提出的.问题是:在8*8的棋盘上摆放8个皇后.使其不能互相攻击,即随意的两个皇后不能处在允许行.同一列,或允许斜线上. 能够把八皇后问题拓展 ...
- 求解n皇后
要求:在国际象棋上摆放n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法 思路:很直观的想法就是在棋盘上一个一个皇后的摆,如果冲突,则摆放在另一个位置,直至 ...
- CSharp遗传算法求解背包问题
断断续续写了四天,感觉背包问题是最适合了解遗传算法的问题模型 using System; using System.Collections.Generic; using System.Linq; us ...
随机推荐
- 应用JConsole学习Java GC
应用JConsole学习Java GC 关于Java GC的知识,好多地方都讲了很多,今天我用JConsole来学习一下Java GC的原理. GC原理 在我的上一篇中介绍了Java运行时数据区,在了 ...
- BestCoder Round #69 (div.2) Baby Ming and Weight lifting(hdu 5610)
Baby Ming and Weight lifting Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K ( ...
- [iOS基础控件 - 6.12.4] NavigationController vs TabBarController
A.属性 1. Item NavigationController: navigationItem (不需要创建) title rightBarButtonItems/ rightBarButtonI ...
- [iOS基础控件 - 6.11.4] storyboard 的 Segue
A.概念 storyboard中的跳转事件连线,都是一个UIStoryboardSegue对象(Segue) 来源控制器 触发控制器 目标控制器 跳转到的控制器 Seg ...
- mysql数据库表间内外链接详解
1. 内连接(自然连接) 2. 外连接 (1)左外连接 (左边的表不加限制)(2)右外连接(右边的表不加限制)(3)全外连接(左右两表都不加限制) 3. 自连接(同一张表内的连接) SQL的标准语法: ...
- hdu 2553 N皇后问题 (经典DFS)
题目链接:点击链接 思路:用一维数组hang[num] = i,num表示第num行,i表示第i列,计算n = 1~10皇后的不同放置数量,然后打表 #include<stdio.h> # ...
- oracle分区表相关
1.查询某个表各分区数据量 select count(*) from table_name partition(分区名) 可以使用sql生成所有分区查询语句: 2.分区表truncate 分区 alt ...
- Weka – 分类
1. weka简单介绍 1) weka是新西兰怀卡托大学WEKA小组用JAVA开发的机器学习/数据挖掘开源软件. 2) 相关资源链接 http://sourceforge.net/pro ...
- Openfire服务器MySQL优化
Openfire服务器MySQL优化: [root@iZ28g4ctd7tZ ~]# mysql -u root -p XXXXX mysql> show processlist; +----- ...
- decide your linux OS is GUI or not
Try: ps -ef|grep X The ps command will display information about a selection of the active process ...