遗传算法-01背包

遗传算法

算法思想
遗传算法(Genetic Algorithm, GA)是模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。
其主要特点是直接对结构对象进行操作,不存在求导和函数连续性的限定;具有内在的隐并行性和更好的全局寻优能力;采用概率化的寻优方法,不需要确定的规则就能自动获取和指导优化的搜索空间,自适应地调整搜索方向。
遗传算法以一种群体中的所有个体为对象,并利用随机化技术指导对一个被编码的参数空间进行高效搜索。其中,选择、交叉和变异构成了遗传算法的遗传操作;参数编码、初始群体的设定、适应度函数的设计、遗传操作设计、控制参数设定五个要素组成了遗传算法的核心内容。

设计思路

遗传算法是从代表问题可能潜在的解集的一个种群开始的,一个种群由基因编码的一定数量的个体组成。每个个体实际上是染色体带有特征的实体。
初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。

这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。

遗传算法应用步骤:
    1)确定决策变量及各种约束条件,即个体的表现型X和问题的解空间;
    2)建立优化模型 (目标函数最大OR 最小) 数学描述形式 量化方法;
    3)染色体编码方法;
    4)解码方法;
    5)个体适应度的量化评价方法 F(x)
    6)设计遗传算子;
    7)确定有关运行参数。

程序代码(使用遗传算法解决01背包问题)

#include <windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>



#define  S				5			//种群的规模
#define  Pc				0.8			//交叉概率
#define  Pm				0.05			//突变概率
#define  KW             1000			//背包最大载重1000
#define  N              50			//物体总数
#define	 T				800			//最大换代数
#define	 ALIKE	        0.05			//判定相似度
int		 stop=0;						//初始化函数中初始化为所有价值之和
int		 t=0;						//目前的代数
int value[]={
220,208,198,192,180,180,165,162,160,158,155,130,125,122,120,118,115,110,105,101,100,100,98,96,95,90,88,82,80,77,75,73,72,70,69,66,65,63,60,58,56,50,30,20,15,10,8,5,3,1};
int weight[]={
80,82,85,70,72,70,66,50,55,25,50,55,40,48,50,32,22,60,30,32,40,38,35,32,25,28,30,22,25,30,45,30,60,50,20,65,20,25,30,10,20,25,15,10,10,10,4,4,2,1};



struct individual				//个体结构体
{
	bool chromsome[N];		//染色体编码
	double fitness;				//适应度//即本问题中的个体所得价值
	double weight;			//总重量
};
int best=0;
int same=0;
individual X[S],Y[S],bestindividual;

/************************************************************************/
int  comp(individual bestindividual,individual temp);	//比较函数
void checkalike(void);							//检查相似度函数
void GenerateInitialPopulation(void); 				//初始种群
void CalculateFitnessValue(void);					//适应度
void SelectionOperator(void);						//选择
void CrossoverOperator(void);					//交叉
void MutationOperator(void);					//变异
void FindBestandWorstIndividual(void);				//寻找最优解
void srand(unsigned int seed);					//随机生成
/************************************************************************/


int comp(individual bestindividual,individual temp)//比较函数
{
	int fit=0,w=0;//第一种不变:操作后不满足重量函数,第二种:操作后适应度小于操作前
	for(int i=0;i<N;i++){
    	fit+=temp.chromsome[i]*value[i];
	    w+=temp.chromsome[i]*weight[i];
	}
	if(w>KW)return -1;
	return (bestindividual.fitness>fit?-1:1);//如果小于原来值或者不满足重量函数,则返回-1
}

/************************************************************************/
void Checkalike(void)
{
	int i=0,j=0;
	for( i=0;i<S;i++)//相似度校验
	{
		for(j=0;j<N;j++)
		{
			bool temp=X[i].chromsome[j];
			for(int k=1;k<S;k++)
			{
				if(temp!=X[k].chromsome[j])
					break;
			}
		}
		if(j==N)
		   same++;
	}
	if(same>N*ALIKE)//大于ALIKE作为判定为早熟
	{
		int minindex=0;
		for(int n=0;n<S;n++)
		  if(X[n].fitness<X[minindex].fitness)
		       minindex=n;//确定最小
		for (j=0; j<N;j++)//重新生成
		{
			bool m=(rand()%10<5)?0:1;
			X[minindex].chromsome[j]=m;
			X[minindex].weight+=m*weight[j];//个体的总重量
			X[minindex].fitness+=m*value[j]; //个体的总价值
		}

	}
}

/************************************************************************/
void GenerateInitialPopulation(void)//初始种群,保证每个值都在符合条件的解
{
	int i=0,j=0; bool k;
	for(i=0;i<N;i++)stop+=value[i];//设置理论最优值
	for (i=0; i<S; i++)
	{
		int w=0,v=0;
		for (j=0; j<N;j++)
		{
			k=(rand()%10<5)?0:1;
			X[i].chromsome[j]=k;
			w+=k*weight[j];//个体的总重量
			v+=k*value[j]; //个体的总价值
		}
		if(w>KW) i--;	   //如果不是解,重新生成
		else
		{
			X[i].fitness=v;
			X[i].weight=w;
			if(v==stop)
            {
			    bestindividual=X[i];
				return;
			}//这种情况一般不会发生
		}
	}
}
/************************************************************************/

void CalculateFitnessValue()
{
	int i=0,j=0;
	for (i=0; i<S; i++)
	{
		int w=0,v=0;
		for (j=0; j<N;j++)
		{
			w+=X[i].chromsome[j]*weight[j];//个体的总重量
			v+=X[i].chromsome[j]*value[j]; //个体的总价值
		}
		X[i].fitness=v;
		X[i].weight=w;
		if(v==stop)
		{
		    bestindividual=X[i];
			return;
		}//符合条件情况下最优解这种情况一般不会发生
		if(w>KW) X[i]=bestindividual;//如果不是解,找最好的一个解代之
	}
}
/************************************************************************/


void SelectionOperator(void)
{
	int i, index;
	double p, sum=0.0;
	double cfitness[S];//选择、累积概率
	individual newX[S];
	for (i=0;i<S;i++)
	    sum+=X[i].fitness;//适应度求和

	for (i=0;i<S; i++)
	    cfitness[i]=X[i].fitness/sum; //选择概率

	for (i=1;i<S; i++)
	    cfitness[i]=cfitness[i-1]+cfitness[i];//累积概率

	for (i=0;i<S;i++)
	{
		p=(rand()%1001)/1000.0;//产生一个[0,1]之间的随机数
		index=0;
		while(p>cfitness[index])//轮盘赌进行选择
		{
			index++;
		}
		newX[i]=X[index];
	}
	for (i=0; i<S; i++)
	   X[i]=newX[i];//新的种群
}

/************************************************************************/
void CrossoverOperator(void)//交叉操作
{
	int i=0, j=0,k=0;individual temp;
	for(i=0; i<S; i++)
	{
		int p=0,q=0;
		do
		{
			p=rand()%S;//产生两个[0,S]的随机数
			q=rand()%S;
		}while(p==q);
		int w=1+rand()%N;//[1,N]表示交换的位数
		double r=(rand()%1001)/1000.0;//[0,1]
		if(r<=Pc)
		{
			for(j=0;j<w;j++)
			{
				temp.chromsome[j]=X[p].chromsome[j];//将要交换的位先放入临时空间
				X[p].chromsome[j]=X[q].chromsome[j];
				X[q].chromsome[j]=temp.chromsome[j];
			}
		}
		if(p==best)
			if(-1==comp(bestindividual,X[p]))//如果变异后适应度变小
				X[p]=bestindividual;

		if(q==best)
			if(-1==comp(bestindividual,X[q]))//如果变异后适应度变小
				X[q]=bestindividual;
	}
}
/************************************************************************/


void MutationOperator(void)
{
	int i=0, j=0,k=0,q=0;
	double p=0;
	for (i=0; i<S; i++)
	{
		for (j=0; j<N; j++)
		{
			p=(rand()%1001)/1000.0;
			if (p<Pm)//对每一位都要考虑
			{
				if(X[i].chromsome[j]==1)X[i].chromsome[j]=0;
				else	X[i].chromsome[j]=1;
			}
		}
		if(i==best)
			if(-1==comp(bestindividual,X[i]))//如果变异后适应度变小
				X[i]=bestindividual;
	}
}
/************************************************************************/

void FindBestandWorstIndividual(void)
{
	int i;
	bestindividual=X[0];
	for (i=1;i<S; i++)
	{
		if (X[i].fitness>bestindividual.fitness)
		{
			bestindividual=X[i];
			best=i;
		}
	}
}


/*主函数*****************************************************************/
int main()
{

  t=0;
  GenerateInitialPopulation(); //初始群体包括产生个体和计算个体的初始值
  while (t<=T)
  {
		FindBestandWorstIndividual();	//保存当前最优解
		SelectionOperator();			//选择
		CrossoverOperator();			//交叉
		MutationOperator();			   //变异
		Checkalike();				  //检查相似度
		CalculateFitnessValue();	 //计算新种群适应度
		t++;
  }
  FindBestandWorstIndividual();			//找到最优解

  printf(" 物品价值:");
  for(int k=0;k<N;k++)
  {
      printf(" %d ",value[k]);
  }
   printf("\n");
   printf(" 物品重量:");
   for(int k=0;k<N;k++)
   {
     printf(" %d  ",weight[k]);
   }
   printf("\n");
   printf("背包容量 %d\n",1000);   	//输出最优值
   printf("-----------------------------\n");


  printf("最优值 %f\n",bestindividual.fitness);   	//输出最优值
  printf("对应重量 %f\n",bestindividual.weight);       //对应重量

  printf("线性解:");
  for(int k=0;k<N;k++)
  {
     if(bestindividual.chromsome[k]==1){  //输出最优解
     	 printf(" %d ",1);
     }else{
     	 printf(" %d ",0);
     }
  }
  printf("\n");
  printf("\n");

  return 0;
}
/*结束***********************************************************************/




测试例

物品价值:

 220  208  198  192  180  180  165  162  160  158  155  130  125  122  120  118  115  110  105  101  100  100  98  96  95  90  88  82  80  77  75  73  72  70  69  66  65  63  60  58  56  50  30  20  15  10  8  5  3  1

物品重量:

 80   82   85   70   72   70   66   50   55   25   50   55   40   48   50   32   22   60   30   32   40   38   35   32   25   28   30   22   25   30   45   30   60   50   20   65   20   25   30   10   20   25   15   10   10   10   4   4   2   1

运行结果

最优值 3078.000000
对应重量 1000.000000
线性解: 1  0  0  1  1  0  1  1  1  1  1  0  1  1  1  1  1  0  1  1  0  0  0  1  1  1  1  1  1  1  0  0  0  0  1  0  1  1  0  1  0  0  0  0  0  0  1  1  1  1

分析
试验中用到的物品的重量和价值分别存储于以下两个数组之中。

int value[]={
220,208,198,192,180,180,165,162,160,158,155,130,125,122,120,118,115,110,105,101,100,100,98,96,95,90,88,82,80,77,75,73,72,70,69,66,65,63,60,58,56,50,30,20,15,10,8,5,3,1};
int weight[]={
80,82,85,70,72,70,66,50,55,25,50,55,40,48,50,32,22,60,30,32,40,38,35,32,25,28,30,22,25,30,45,30,60,50,20,65,20,25,30,10,20,25,15,10,10,10,4,4,2,1};

遗传算法有许多不足,算法对新空间的探索能力是有限的,也容易收敛到局部最优解。涉及到大量个体的计算,当问题复杂时,计算时间很长。
但是他也有很多优点:

  1. 与问题领域无关切快速随机的搜索能力。
  2. 搜索从群体出发,具有潜在的并行性,可以进行多个个体的同时比较,robust.
  3. 搜索使用评价函数启发,过程简单
  4. 使用概率机制进行迭代,具有随机性。
  5. 具有可扩展性,容易与其他算法结合。

参考:
短短的路走走停停被抢注啦
鹤鹤有明
wangqiuyun

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值