本文主要介绍遗传算法的一些基本思想,主要是代码思想方面的,并不用于考试....在我的资源中可以找到一份课件(并不是我们学校的,是老师给的,我们貌似并不开这门课)
另外会在下一篇附上用遗传算法解决tsp问题的代码。
遗传算法的思想其实和生物学有密切的联系(话说我高中选的是生物,已经忘光了哈),遗传算法相比与动态规划,贪心之类的算法,区别主要在于,贪心之类的一开始给出一种计算方式,而我们从已知条件,通过这种计算方式最终得到解,并且解一定是正确的(如果贪心策略经过验证)。而遗传算法一开始会给出一个种群(其实质就是解的集合),当然这些解不一定是正确的,所以我们通过一步步演变,就像是优胜劣汰,最终得到尽可能正确的解。
先介绍一些遗传算法的名词(后面会举例子方便理解)。
基因:染色体内部的某个表现,如何将问题表示成基因需要一定的技巧。
染色体:其实质就是一个解,也就是一个个体,遗传算法优胜劣汰直接作用的对象
适应性:就是一个评估函数,给出一条染色体,看看他是不是我们需要的,如果不需要,那么被淘汰的可能性好高(注意并不是一定被淘汰,就算适应性很低,也有可能存活)
选择:即染色体的选择
交叉:两个染色体的某一处断裂,各自交换断裂的部分(这个地方交换的方法其实也很多,但大概意思都差不多,按照程序书写方便与最终效果选择)
变异:某一个染色体的某一个基因(或多个,也是根据情况选择)发生改变。
简单来说现在有一个汉堡店,他有三个选择,汉堡包价格50美分还是1美元,餐馆大还是小,服务快还是慢,最终考虑汉堡包为了尽可能的盈利,应该怎样选择。
对于这个问题,汉堡店就是一个染色体,它里面有三个基因,分别是汉堡包价格,餐馆大小,服务快慢。
适应性就是我们设计函数,比如当汉堡包价格低,餐馆服务快,大餐馆会怎样(以此类推,应该共有8种情况吧)
那么如何表现基因呢,常用的方法就是二进制,比如50美分就是1,1美元就是0,大餐馆就是1,小餐馆就是0,服务快就是1,服务慢就是0,
那么低价格,服务快,大餐馆就是111,这就是一个解
下面附一个
生成初始群,这个你随机生成即可,适应度这里不太好表示(对于大多数情况适应性函数也只能取个大概)
选择常用的方法是轮盘赌选择法。
终止就是你设计一下最多迭代次数,超过这个次数停止。
步骤: 1、求群体中所有个体的适应值的总和 S ;
2、产生一个在 0 与 S 之间的随机数 m ;
3、从群体中编号为 1 的个体开始,将其适应
值与后继个体的适应值相加,直到累加和等
于或大于 m , 则停止. 其中那个最后加进去
的个体即为选择的个体 .
这样能达到可能存活性为80%它被选择的可能性就为80%
交叉 比如111,001那么我们交叉第二位(含之后的)就能得到101,011)
交叉方式的有很多,你可以自己选择在哪个点断开,也可以选择几个点断裂,比如两个点断裂,就两边交换,中间保留(tsp的代码采用的是这种方法)
变异 这个比较好理解,就是你随机一个位置这个位置上的基因发生变化,有时是引入新的基因,有时是随机两个位置,这两个位置交换(比如tsp问题,因为那个要求染色体是全排列,你肯定不能随便修改里面的基因)
以上就是一个轮回。
下面讨论tsp问题,对于tsp问题,显然用二进制来表示是不合适的,一般对于区间在[a,b]内的书如果用二进制表示,则他的位数n应满足
(b-a)/(2^n)<1,一般城市数量都相当大,所以无法用二进制表示,这里采用的是全排列的方式,每一个城市就是基因,他们访问的顺序就是染色体。
而初始种群设置为10个染色体,而适应函数肯定与路程有关,且路程越大,适应性越低,所以算出每一个路程/总路程后,有两种方式,一种是取倒数,一种是1-这个数
最后不要将概率之和统一为1(每一个操作完的适应性值/总的适应性值).
交叉算法如下:
注意每一次修正后,还要考虑修正的值是否与之前两个断点之间的基因重复(刚才认为不重复是因为与原来的值重复,而现在换了,比如图中第二种情况)
下面附代码,参考http://blog.csdn.net/mylovestart/article/details/8977005(讲得非常详细,但注意交配有问题)
http://blog.csdn.net/yeruby/article/details/13161853(交配进行了修正)
#include
#include
#include
#include
#include
#define cities 10//城市的个数
#define num 10//种群的大小
#define MAX 100//最大迭代次数
#define pm 0.05//变异的概率
#define pc 0.8//交配的概率
int distance[cities+1][cities+1];
typedef struct node//染色体的结构,也就是一组解
{
int city[cities];//每一个基因,也就是10座城市
int adapt;//该组解的适应性
double p;//在种群中幸存的概率
}node;
node group[num],grouptemp[num];//grouptemp是为了在选择是临时存储group内的数据
void init()
{
int i,j;
memset(distance,0,sizeof(distance));
srand(time(NULL));
for (i=0;it)//最后添加进去的存活
{
xuan[i]=j;//第i次选择的是第j条染色体
break;
}
}
for (i=0;ipoint2)
{
temp=point1;
point1=point2;
point2=temp;
}
temp1=jiaopeiflag[c];
temp2=jiaopeiflag[d];
c=c+2;
d=d+2;
memset(map1,-1,sizeof(map1));
memset(map2,-1,sizeof(map2));
for (k=point1;k<=point2;k++)
{
map1[group[temp1].city[k]]=group[temp2].city[k];//对于map1记录第一个染色体的某个基因对应第二个染色体的某个基因(关键!)
map2[group[temp2].city[k]]=group[temp1].city[k];//对于map2记录第二个染色体的某个基因对应第二个染色体的某个基因
}
for (k=0;k