优化求解问题的一种方法,模拟生物进化过程,所以称遗传算法。
#ifndef CITY_H
#define CITY_H
struct City
{
int x, y, number;
};
#endif //CITY_H
Individual.h
#ifndef INDIVIDUAL_H
#define INDIVIDUAL_H
#include "global.h"
class Individual
{
public:
Individual();
void initIndividual();
void computeFitness();
bool isContainCity(const int&);
int geneLocation(const int&) const;
void localSearch();
bool operator < (const Individual&);
friend class GA;
private:
int sequence[CityNumber];
double fitness;
};
#endif //INDIVIDUAL_H
#ifndef GA_H
#define GA_H
#include "global.h"
#include "individual.h"
#include
#include
#include
#include
using namespace std;
class GA
{
public:
void initGA();
void printResult(ofstream& fout);
void printResult();
void evolve();
private:
Individual pop[PopSize * 3];
void Search(Individual* offspring, const int& offspringNum);
void PMX(const Individual& parent1, const Individual& parent2, Individual& child1, Individual& child2);
void OX(const Individual &parent1, const Individual &parent2, Individual &child1, Individual &child2);
void crossover(int& currentSize, const int* parentNum, Individual* offspring);
void mutation(Individual* offspring, int& offspringNum);
void rouletteSelection(int*, const int&, const int& num);
void selection(Individual* offspring, const int offspringNum);
};
#endif //GA_H
涉及参数: 交叉概率(corssPM),变异概率(variationPM),精英数量(Elite)
#ifndef GLOBAL_H
#define GLOBAL_H
const int PopSize = 100;
const int CityNumber = 130;
const int MaxGen = 500;
const int LocalSearchTimes = 300;
const int Elite = 5;
const double variationPM = 0.1;
const double crossPM = 0.8;
extern double Distance[CityNumber][CityNumber];
void initCityDist();
#endif // GLOBAL_H
main函数:(在InitCityDist函数中从文件读取了城市信息)
#include "city.h"
#include "GA.h"
#include "individual.h"
#include "global.h"
#include
#include
#include
using namespace std;
int main()
{
ofstream fout("1.txt");
srand((unsigned)time(NULL));
initCityDist();
GA ga;
ga.initGA();
ga.evolve();
ga.printResult(fout);
return 0;
}
#include "city.h"
#include "global.h"
#include
#include
#include
#include
using namespace std;
double Distance[CityNumber][CityNumber];
void initCityDist()
{
double x,y,number;
ifstream cin("input.txt");
City citysInformation[CityNumber];
for(int i = 0; i < CityNumber; ++i)
{
cin >> number >> x >> y;
citysInformation[i].x = x;
citysInformation[i].y = y;
citysInformation[i].number = number;
}
memset(Distance, 0, sizeof(Distance));
for(int i = 0; i < CityNumber; ++i)
for(int j = i+1; j < CityNumber; ++j)
{
Distance[i][j] = Distance[j][i] =sqrt((citysInformation[i].x - citysInformation[j].x)*(citysInformation[i].x - citysInformation[j].x) + (citysInformation[i].y - citysInformation[j].y)*(citysInformation[i].y - citysInformation[j].y) );
}
}
#include "individual.h"
#include "global.h"
#include
#include
#include
#include
using namespace std;
Individual::Individual() : fitness(0) {}
void Individual::initIndividual()
{
for (int i = 0; i < CityNumber; ++i)
sequence[i] = i;
random_shuffle(sequence, sequence + CityNumber);
computeFitness();
}
void Individual::computeFitness()
{
double sumDis = 0;
for(int i = 0; i < CityNumber-1; ++i)
{
sumDis += Distance[sequence[i]][sequence[i+1]];
}
sumDis += Distance[sequence[CityNumber-1]][sequence[0]];
if(sumDis)
fitness = 1.0 / sumDis;
}
bool Individual::isContainCity(const int& city)
{
for(int i = 0; i < CityNumber; ++i)
{
if(sequence[i] == city)
return true;
}
return false;
}
int Individual::geneLocation(const int &gene) const
{
for (int i = 0; i < CityNumber; ++i)
{
if (sequence[i] == gene)
return i;
}
cout << "error" << endl;
return 0;
}
void Individual::localSearch()
{
//int code[CityNumber];
Individual afterReverse;
//memcpy(code, sequence, CityNumber*sizeof(int));
for (int i = 0; i < LocalSearchTimes; ++i)
{
memcpy(afterReverse.sequence, sequence, CityNumber*sizeof(int));
int point1 = rand() % CityNumber;
int point2 = rand() % CityNumber;
if (point1 > point2)
swap(point1, point2);
reverse_copy(sequence + point1, sequence + point2 + 1, afterReverse.sequence + point1);
afterReverse.computeFitness();
if (afterReverse.fitness > fitness)
{
memcpy(sequence, afterReverse.sequence, CityNumber*sizeof(int));
computeFitness();
}
}
}
bool Individual::operator < (const Individual& cmp)
{
return fitness > cmp.fitness;
}
#include "GA.h"
#include
#include
#include
#include
#include
#include
using namespace std;
void GA::initGA()
{
for (int i = 0; i < PopSize; i++)
pop[i].initIndividual();
}
void GA::printResult(ofstream& fout)
{
fout << "Distance is:" << 1.0 / pop[0].fitness << endl;
fout << "The route is:" << endl;
for (int i = 0; i < CityNumber; ++i)
fout << pop[0].sequence[i] + 1 << "->";
for (int i = 0; i < PopSize; ++i)
{
fout << i << ":" << endl;
for (int j = 0; j < CityNumber; ++j)
fout << pop[i].sequence[j] + 1 << " ";
fout << endl;
}
}
void GA::printResult()
{
cout << "Distance is:" << 1.0 / pop[0].fitness << endl;
cout << "The route is:" << endl;
for (int i = 0; i < CityNumber; ++i)
cout << pop[0].sequence[i] + 1 << "->";
for (int i = 0; i < PopSize; ++i)
{
cout << i << ":" << endl;
for (int j = 0; j < CityNumber; ++j)
cout << pop[i].sequence[j] + 1 << " ";
cout << endl;
}
}
void GA::rouletteSelection(int* selectedNum, const int& size, const int& num)
{
double P[3 * PopSize];
double sumfitness = 0;
for(int i =0; i < size; i++)
sumfitness += pop[i].fitness;
P[0] = pop[0].fitness / sumfitness;
for(int i = 1; i < size - 1; ++i)
{
P[i] = pop[i].fitness / sumfitness + P[i-1];
}
P[size - 1] = 1.0;
for (int j = 0; j < num; ++j)
{
double random = rand() % 10000 / 10000.00;
for (int i = 0; i < size; ++i)
{
if(random <= P[i])
{
selectedNum[j] = i;
break;
}
}
}
}
void GA::crossover(int& offspringNum, const int* parentsNum, Individual* offspring)
{
for (int i = 0; i < PopSize - 2; i += 2)
{
if (rand() % 100 / 100.0 < crossPM)
{
Individual parent1 = pop[parentsNum[i]];
Individual parent2 = pop[parentsNum[i + 1]];
Individual child1, child2;
PMX(parent1, parent2, child1, child2);
//OX(parent1, parent2, child1, child2);
child1.computeFitness();
child2.computeFitness();
offspring[offspringNum++] = child1;
offspring[offspringNum++] = child2;
}
}
}
void GA::evolve()
{
for (int times = 0; times < MaxGen; ++times)
{
int offspringNum = 0;
Individual offspring[PopSize * 3];
int parentsNum[PopSize];
rouletteSelection(parentsNum, PopSize, PopSize);
crossover(offspringNum, parentsNum, offspring);
mutation(offspring, offspringNum);
Search(offspring, offspringNum);
selection(offspring, offspringNum);
}
}
void GA::mutation(Individual* offspring, int& offspringNum)
{
int initial = offspringNum;
for (int i = 0; i < initial; ++i)
{
if (rand() % 100 / 100.0 < variationPM)
{
int swapCityId1 = rand() % CityNumber;
int swapCityId2 = rand() % CityNumber;
Individual child = offspring[i];
swap(child.sequence[swapCityId1], child.sequence[swapCityId2]);
child.computeFitness();
offspring[offspringNum++] = child;
}
}
}
void GA::selection(Individual* offspring, const int offspringNum)
{
memcpy(offspring + offspringNum, pop, PopSize*sizeof(Individual));
partial_sort(offspring, offspring + Elite, offspring + PopSize + offspringNum);
int selectedNum[PopSize - Elite];
rouletteSelection(selectedNum, PopSize + offspringNum, PopSize - Elite);
for (int i = 0; i < Elite; ++i)
pop[i] = offspring[i];
for (int i = Elite, j = 0; i < PopSize; ++i, ++j)
pop[i] = offspring[selectedNum[j]];
}
void GA::Search(Individual* offspring, const int& offspringNum)
{
for (int i = 0; i < offspringNum; ++i)
{
offspring[i].localSearch();
}
}
void GA::PMX(const Individual & parent1, const Individual & parent2, Individual & child1, Individual & child2)
{
memset(child1.sequence, -1, sizeof(child1.sequence));
memset(child2.sequence, -1, sizeof(child2.sequence));
int point1 = rand() % CityNumber;
int point2 = rand() % CityNumber;
if (point1 > point2)
swap(point1, point2);
for (int i = point1; i < point2; ++i)
{
child1.sequence[i] = parent2.sequence[i];
child2.sequence[i] = parent1.sequence[i];
}
for (int i = 0; i < CityNumber; ++i)
{
if (i >= point1 && i < point2)
continue;
int matching = parent1.sequence[i];
while (child1.isContainCity(matching))
matching = parent1.sequence[parent2.geneLocation(matching)];
child1.sequence[i] = matching;
matching = parent2.sequence[i];
while (child2.isContainCity(matching))
matching = parent2.sequence[parent1.geneLocation(matching)];
child2.sequence[i] = matching;
}
}
void GA::OX(const Individual& parent1, const Individual& parent2, Individual& child1, Individual& child2)
{
memset(child1.sequence, -1, sizeof(child1.sequence));
memset(child2.sequence, -1, sizeof(child2.sequence));
int point1 = rand() % CityNumber;
int point2 = rand() % CityNumber;
if (point1 > point2)
swap(point1, point2);
for (int i = point1; i < point2; ++i)
{
child1.sequence[i] = parent2.sequence[i];
child2.sequence[i] = parent1.sequence[i];
}
int k = 0;
int j = 0;
for (int i = point2; i < CityNumber; ++i)
{
while (child1.isContainCity(parent1.sequence[k])) ++k;
while (child2.isContainCity(parent2.sequence[j])) ++j;
child1.sequence[i] = parent1.sequence[k++];
child2.sequence[i] = parent2.sequence[j++];
}
for (int i = 0; i < point1; ++i)
{
while (child1.isContainCity(parent1.sequence[k])) ++k;
while (child2.isContainCity(parent2.sequence[j])) ++j;
child1.sequence[i] = parent1.sequence[k++];
child2.sequence[i] = parent2.sequence[j++];
}
}