C++实现多目标遗传算法(0/1背包问题)
2017-10-31 20:00
736 查看
(背包问题):背包只能容得下一定重量b的物品,物品有m种,每种物品有自己的重量w(i)和价值v(i),从这些物品中选择装入背包,是背包不超过重量b,但价值又要最大。
上面为单目标的0/1规划问题,也就是说只考虑物体的重量不考虑物体的体积,形状等问题,一般而言,利用动态规划可以很好地解决背包问题,但是如果物体过多,使用动态规划将浪费很大的资源.
遗传算法作经典的人工智能算法,可以很好的解决当物体较多的0/1规划问题。
(遗传算法概述):
遗传算法使用的就是生物学中适者生存的法则。但是和生物中一些专业人术语有些区别:
种群(Population):生物的进化以群体的形式进行,这样的一个群体称为种群。
个体:组成种群的单个生物。
基因 ( Gene ) :一个遗传因子。
染色体 ( Chromosome ) :包含一组的基因。
生存竞争,适者生存:对环境适应度高的、牛B的个体参与繁殖的机会比较多,后代就会越来越多。适应度低的个体参与繁殖的机会比较少,后代就会越来越少。
遗传与变异:新个体会遗传父母双方各一部分的基因,同时有一定的概率发生基因变异。
具体流程如下:
![](https://img-blog.csdn.net/20171106125324577?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveXV5dXNoaWt1YW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
(注:图片来之百度)
(具体背包问题概述):
32件物体,属性重量,体积,价值(普通的0/1规划只考虑重量或者体积)。背包最大体积:75,最大重量:80,把物体装入背包,保证价值的最大化。
上面为单目标的0/1规划问题,也就是说只考虑物体的重量不考虑物体的体积,形状等问题,一般而言,利用动态规划可以很好地解决背包问题,但是如果物体过多,使用动态规划将浪费很大的资源.
遗传算法作经典的人工智能算法,可以很好的解决当物体较多的0/1规划问题。
(遗传算法概述):
遗传算法使用的就是生物学中适者生存的法则。但是和生物中一些专业人术语有些区别:
种群(Population):生物的进化以群体的形式进行,这样的一个群体称为种群。
个体:组成种群的单个生物。
基因 ( Gene ) :一个遗传因子。
染色体 ( Chromosome ) :包含一组的基因。
生存竞争,适者生存:对环境适应度高的、牛B的个体参与繁殖的机会比较多,后代就会越来越多。适应度低的个体参与繁殖的机会比较少,后代就会越来越少。
遗传与变异:新个体会遗传父母双方各一部分的基因,同时有一定的概率发生基因变异。
具体流程如下:
(注:图片来之百度)
(具体背包问题概述):
32件物体,属性重量,体积,价值(普通的0/1规划只考虑重量或者体积)。背包最大体积:75,最大重量:80,把物体装入背包,保证价值的最大化。
//主函数入口 #include"gene.h" #include <string.h> #include <iostream> using namespace std; int main(int argc, char*argv[]) { Gene *gene = new Gene; //实例化类,返回指针 int gen = 0; int oldMaxPop, k; double oldMax; srand((unsigned)time(NULL)); gene->initPop(); memcpy(&gene->newPop, &gene->oldPop, POP_SIZE * sizeof(struct Gene::population)); gene->statistics(gene->newPop); //计算种群的最大适应度和最小适应度以及适应度的下表号。 gene->report(gene->newPop, gen); while (gen < CENERAION_NUM) { gen += 1; if (gen % 100 == 0) { srand((unsigned)time(NULL)); } oldMax = gene->maxFitness; //oldmax为种群中最大适应度 oldMaxPop = gene->maxPop; //oldMaxPop指种群中最大适应度的个体 gene->generation(); gene->statistics(gene->newPop); if (gene->maxFitness < oldMax) { for (k = 0; k < CHROM_SIZE; k++) { gene->newPop[gene->minPop].chrom[k] = gene->oldPop[oldMaxPop].chrom[k]; } gene->newPop[gene->minPop].fitness = gene->oldPop[oldMaxPop].fitness; gene->newPop[gene->minPop].weight = gene->oldPop[oldMaxPop].weight; gene->newPop[gene->minPop].volume = gene->oldPop[oldMaxPop].volume; gene->newPop[gene->minPop].parent1 = gene->oldPop[oldMaxPop].parent1; gene->newPop[gene->minPop].parent2 = gene->oldPop[oldMaxPop].parent2; gene->newPop[gene->minPop].cross = gene->oldPop[oldMaxPop].cross; gene->statistics(gene->newPop); } else if(gene->maxFitness > oldMax){ gene->report(gene->newPop, gen); } memcpy(&gene->oldPop, &gene->newPop, POP_SIZE * sizeof(struct Gene::population)); } delete[] gene; //销毁对象占用空间 system("pause"); return 0; }
/******** 头文件的定义 ********/ #pragma once #ifndef GENE_H #define GENE_H #include <stdio.h> #include <math.h> #include <stdlib.h> #include <time.h> #include <conio.h> #define POP_SIZE 200 //定义种群规模 #define RRO_CROSS 0.618 //交叉概率 #define PRO_MUTATE 0.03 //变异概率 #define CHROM_SIZE 32 //给定染色体长度 #define CENERAION_NUM 1000 //定义繁殖代数 typedef unsigned int UINT; class Gene { public: Gene(); ~Gene(); public: struct population { //定义私有的个体类 UINT chrom[CHROM_SIZE]; //定义个体的基因组 double weight; //背包的重量 double volume; //背包的体积 double fitness; //个体的适应度 UINT parent1, parent2, cross; //双亲以及交叉的节点 }; population oldPop[POP_SIZE], newPop[POP_SIZE]; int weight[CHROM_SIZE] = { 22, 15, 4, 5, 10, 19, 21, 20, 8, 13, 2, 3, 3, 17, 12, 5, 12, 4, 1< 4000 /span>, 21, 14, 23, 17, 15, 20, 22, 25, 0, 22, 15, 25, 13 }; int volume[CHROM_SIZE] = { 11, 22, 12, 21, 21, 13, 1, 10, 13, 8, 6, 25, 13, 27, 12, 23, 12, 24, 23, 11, 6, 24, 28, 10, 20, 13, 25, 23, 5, 26, 30, 15 }; int profit[CHROM_SIZE] = { 8, 9, 15, 6, 16, 9, 1, 4, 14, 9, 3, 7, 12, 4, 15, 5, 18, 5, 15, 4, 6, 2, 12, 14, 11, 9, 13, 13, 14, 13, 19, 4 }; int containW = 80, containV = 75; double sumFitness; //种群总适应度 double minFitness; //最小适应度 double maxFitness; //最大适应度 double avgFitness; //平均适应度 double alpha; //计算适应度时的惩罚系数 int minPop; //种群内最大和最小的适应个体 int maxPop; void initPop(); //总群初始化函数 //int calWeight(UINT *chr); //计算个体体积,重量,以及收益的函数 //int Gene::calVolume(UINT *chr); int calSum(UINT *ch, int *pt); double calFit(UINT *ch); void statistics(struct population *pop); //计算种群最大适应度和最小适应度的函数 void report(struct population *pop, int gen); //为输出的函数 int selection(int pop); //通过选择总群中符合要求的父母进行繁殖 函数返回父母的位置 int crossOver(UINT *parent1, UINT *parent2, int i); //传入要更改的个体位置,随机产生交叉位置 int excise(double probability);// 传入概率参数,进行交叉或者变异 int mutation(UINT i); //传入参数为基因组基因的位置,逐个基因判断变异概率 void generation(); //种群群体更新的函数 }; #endif // !GENE_H
//类中代码的实现 #include "gene.h" #include<bitset> #include<iostream> using namespace std; Gene::Gene() { cout << "begin" << endl; } Gene::~Gene() { } int Gene::calSum(UINT *ch, int *pt) //ch为装入背包中的一个可能的解 pt为重量或者体积的指针 { int popSum = 0; for (int i = 0; i < CHROM_SIZE; i++) { popSum += (*ch) * pt[i]; ch++; } return popSum; } void Gene::initPop() { int tmpWeight = 0; int tmpVolume = 0; int m = 0; bool isPop = false; //最初代的种群的初始化 for (int i = 0; i < POP_SIZE; i++) { //这里的POP_SIZE是种群规模 while (!isPop){ for (int j = 0; j < CHROM_SIZE; j++) { m = rand() % 1001; //rand为初始化函数,这里设置生成0的概率要大一些 if (m <= 499) oldPop[i].chrom[j] = 0; else oldPop[i].chrom[j] = 1; oldPop[i].parent1 = 0; oldPop[i].parent2 = 0; oldPop[i].cross = 0; } //剔除重量和体积大于背包容量的体积的个体 tmpWeight = calSum(oldPop[i].chrom, weight); tmpVolume = calSum(oldPop[i].chrom, volume); if ((tmpWeight <= containW) && (tmpVolume <= containV)) { oldPop[i].fitness = calSum(oldPop[i].chrom, profit); oldPop[i].weight = tmpWeight; oldPop[i].volume = tmpVolume; oldPop[i].parent1 = 0; oldPop[i].parent2 = 0; oldPop[i].cross = 0; isPop = true; } } isPop = false; } } void Gene::statistics(struct population *pop) { double tmpFitness; minPop = 0; maxPop = 0; sumFitness = pop[0].fitness; minFitness = pop[0].fitness; maxFitness = pop[0].fitness; for (int i = 1; i < POP_SIZE; i++) { sumFitness += pop[i].fitness; tmpFitness = pop[i].fitness; //挑选出最大的适应度个体 if ((tmpFitness > maxFitness) && ((int)(tmpFitness * 10) % 10 == 0)){ maxFitness = pop[i].fitness; maxPop = i; } //挑选出最小的适应度个体 if (tmpFitness < minFitness) { minFitness = pop[i].fitness; minPop = i; } //计算出平均的适应度 avgFitness = sumFitness / (float)POP_SIZE; } } void Gene::report(struct population *pop, int gen) { int popWeight = 0; cout << "The generation is " << gen << endl; //显示种群的代数 cout << "The population chrom is: " << endl; for (int j = 0; j < CHROM_SIZE; j++) { if (j % 4 == 0) cout << " "; cout << pop[maxPop].chrom[j]; } cout << endl; cout << "The population's max fitness is: " << (int)pop[maxPop].fitness << endl; cout << "The population's max weight is: " << (int)pop[minPop].weight << endl; cout << "The population's max volume is: " << (int)pop[minPop].weight << endl; } int Gene::selection(int pop) //使用轮赌法进行选择 { double wheelPos, randNumber, partsum = 0; int i = 0; randNumber = (rand() % 2001) / 2000.0; wheelPos = randNumber*sumFitness; do { partsum += oldPop[i].fitness; i++; } while ((partsum < wheelPos) && (i < POP_SIZE)); return i - 1; } int Gene::crossOver(UINT *parent1, UINT *parent2, int i) { int j; //基因组的基因位置 int crossPos; //交叉点的位置 if (excise(RRO_CROSS)) { crossPos = rand() % (CHROM_SIZE - 1); } else { crossPos = CHROM_SIZE - 1; } for (j = 0; j <= crossPos; j++) { newPop[i].chrom[j] = parent1[j]; } for (j = crossPos + 1; j < CHROM_SIZE; j++) { newPop[i].chrom[j] = parent2[j]; } newPop[i].cross = crossPos; return 1; } int Gene::excise(double probability) //传入概率参数,概率选择实验 { double pp; pp = (double)(rand() % 20001 / 20000.0); if (pp <= probability) { return 1; } else { return 0; } } int Gene::mutation(UINT alleles) { if (excise(PRO_MUTATE)) { alleles == 0 ? alleles = 1 : alleles = 0; } return alleles; } void Gene::generation() { UINT mate1, mate2; UINT i, j; int tmpWeight = 0; int tmpVolume = 0; bool notGen; for (i = 0; i < POP_SIZE; i++) { notGen = false; while (!notGen){ mate1 = selection(i); //选择有几率产生优良后代的双亲的位置 mate2 = selection(i + 1); crossOver(oldPop[mate1].chrom, oldPop[mate2].chrom, i); for (j = 0; j < CHROM_SIZE; j++) { newPop[i].chrom[j] = mutation(newPop[i].chrom[j]); //给基因变异的概率 cbfa } tmpWeight = calSum(newPop[i].chrom, weight); tmpVolume = calSum(newPop[i].chrom, volume); if ((tmpWeight <= containW) && (tmpVolume <= containV)) { newPop[i].fitness = calSum(newPop[i].chrom, profit); newPop[i].weight = tmpWeight; newPop[i].volume = tmpVolume; newPop[i].parent1 = mate1; newPop[i].parent2 = mate2; notGen = true; } } } }
相关文章推荐
- 01背包问题 及c++ 代码实现
- 0-1背包问题与完全背包问题C++实现 动态规划
- 【高级算法】遗传算法解决3SAT问题(C++实现)
- 0-1背包问题与完全背包问题C++实现 动态规划
- 01背包问题与分数背包问题 C++实现
- dynamic programming --knapsack problem 背包问题(c++实现)
- c++实现0-1背包问题完整源码(动态规划实现)
- 0/1背包问题 - 分枝定界(C++实现)
- 遗传算法解决TSP问题(c++实现)
- 加了限制条件的0-1背包问题(C++实现)
- 01背包、完全背包、多重背包问题的C++实现
- 贪心算法运用于背包问题(C++实现)
- 01背包问题的C/C++实现
- 0/1背包问题 - 动态规划(C++实现)
- 遗传算法 TSP问题 C++实现 (三)
- c++实现0-1背包问题完整源码(动态规划实现)
- c++实现0-1背包问题完整源码(动态…
- 0/1背包问题 - 暴力法(C++实现)
- c++实现0-1背包问题完整源码续(动态规划+回溯法实现)
- C++ 实现 0-1 背包问题