#include <iostream> #include <ctime> #include <math.h> #include <algorithm> #include <assert.h> #include "City.h" using namespace std; vector<City> vecCityList; //城市信息清单 const int UNIT_NUMBER = 5*2; //确保数目为双数 方便计算遗传交叉 #define HOLD_UNIT_NUMBER 1*2 void InitListCity(){ vecCityList.push_back(City("1",1.0,2.0)); vecCityList.push_back(City("2",3.0,2.0)); vecCityList.push_back(City("3",5.0,2.0)); vecCityList.push_back(City("4",1.0,3.0)); vecCityList.push_back(City("5",2.0,3.0)); vecCityList.push_back(City("6",4.0,3.0)); vecCityList.push_back(City("7",5.0,3.0)); vecCityList.push_back(City("8",1.0,4.0)); vecCityList.push_back(City("9",3.0,4.0)); vecCityList.push_back(City("0",5.0,4.0)); } CITY_PATH CreateRandomCitypath(){ vector<int> vecCityIndex; for(int i = 0;i < vecCityList.size();++i){ vecCityIndex.push_back(i); } CITY_PATH cityPath; for(int i = 0;i < vecCityList.size();++i){ int index = rand()%(vecCityIndex.size()); cityPath.push_back(vecCityIndex[index]); vector<int>::iterator it = vecCityIndex.begin()+index; vecCityIndex.erase(it); } return cityPath; } inline double RandFloat() {return (rand())/(RAND_MAX+1.0);} void CalMethodPrice(vector<CityWalkMethod>& vecCityWalkMethod){ double maxMehtodDistance = 0.0; for(int j = 0 ; j < vecCityWalkMethod.size();++j){ vecCityWalkMethod[j].distance_ = 0.0; CITY_PATH& cwkm = vecCityWalkMethod[j].cityPath_; for(int i = 0;i < cwkm.size()-1;++i){ int cityA = cwkm[i]; int cityB = cwkm[i+1]; double distanceXPow = pow(vecCityList[cityA].x_ - vecCityList[cityB].x_,2); double distanceYPow = pow(vecCityList[cityA].y_ - vecCityList[cityB].y_,2); vecCityWalkMethod[j].distance_ += sqrt((distanceXPow + distanceYPow)); } if(maxMehtodDistance < vecCityWalkMethod[j].distance_ ){ maxMehtodDistance = vecCityWalkMethod[j].distance_; } } for(int i = 0 ; i < vecCityWalkMethod.size();++i){ vecCityWalkMethod[i].pathPrice_ = ( maxMehtodDistance - vecCityWalkMethod[i].distance_)*10; } } CityWalkMethod SelectMethodUnit(vector<CityWalkMethod>& vecCityWalkMethod){ double totalPrice = 0.0; for(int i = 0 ;i < vecCityWalkMethod.size();++i){ totalPrice += vecCityWalkMethod[i].pathPrice_; } double slice = RandFloat()*totalPrice; totalPrice = 0.0; int index = 0; for(int i = 0;i < vecCityWalkMethod.size();++i){ totalPrice += vecCityWalkMethod[i].pathPrice_; if(totalPrice > slice){ index = i; break; } } return vecCityWalkMethod[index]; } void CrossOver(const CityWalkMethod& methodA, const CityWalkMethod& methodB, CityWalkMethod& baby1, CityWalkMethod& baby2){ int beg = rand()% (methodA.cityPath_.size()); int end = rand()% (methodA.cityPath_.size()); while(beg == end){ end = rand()% (methodA.cityPath_.size()); } if(end < beg){ swap(end,beg); } baby1 = methodA; baby2 = methodB; for(int pos = beg;pos<=end;++pos){ int indexA = methodA.cityPath_[pos]; int indexB = methodB.cityPath_[pos]; if(indexA != indexB){ vector<int>::iterator it1 = find(baby1.cityPath_.begin(),baby1.cityPath_.end(),indexA); vector<int>::iterator it2 = find(baby1.cityPath_.begin(),baby1.cityPath_.end(),indexB); swap(*it1,*it2); it1 = find(baby2.cityPath_.begin(),baby2.cityPath_.end(),indexA); it2 = find(baby2.cityPath_.begin(),baby2.cityPath_.end(),indexB); swap(*it1,*it2); } } } void DebugPrintVecCitymethod(const vector<CityWalkMethod>& vecCityWalkMethod){ //======================= cout << endl; for(int i = 0 ; i < vecCityWalkMethod.size();++i){ for(int j =0 ;j < vecCityWalkMethod[i].cityPath_.size();++j){ cout << vecCityWalkMethod[i].cityPath_[j] << " "; } cout << "distance = " << vecCityWalkMethod[i].distance_ << " "; cout << "price = " << vecCityWalkMethod[i].pathPrice_ << endl; } //=========================== } bool CompareMethodPrice(CityWalkMethod a,CityWalkMethod b){ return a.pathPrice_ > b.pathPrice_; } void Mutation( CityWalkMethod& cityWalkMethod){ if( (rand()%100) > 75){ swap(cityWalkMethod.cityPath_[0],cityWalkMethod.cityPath_[1]); } } void SelectAndCrossOver(vector<CityWalkMethod>& vecCityWalkMethod){ vector<CityWalkMethod> tmp; assert(vecCityWalkMethod.size() != 0); assert(vecCityWalkMethod.size() == UNIT_NUMBER); sort(vecCityWalkMethod.begin(),vecCityWalkMethod.end(),CompareMethodPrice); for(int i =0;i < HOLD_UNIT_NUMBER;i++){ //上一代最优走法 优先保留到下一代 tmp.push_back(vecCityWalkMethod[i]); } for(int i = 0 ; i < (UNIT_NUMBER-HOLD_UNIT_NUMBER)/2;i++){ //选择两种方法进行交叉 CityWalkMethod methodA = SelectMethodUnit(vecCityWalkMethod); CityWalkMethod methodB = SelectMethodUnit(vecCityWalkMethod); // while(methodA == methodB){ // methodB = SelectMethodUnit(vecCityWalkMethod); // } CityWalkMethod baby1,baby2; CrossOver(methodA,methodB,baby1,baby2); Mutation(baby1); Mutation(baby2); tmp.push_back(baby1); tmp.push_back(baby2); } vecCityWalkMethod = tmp; assert(vecCityWalkMethod.size() == UNIT_NUMBER); CalMethodPrice(vecCityWalkMethod); } int main(int argc, char *argv[]) { srand( (unsigned)time( NULL ) ); InitListCity(); //初始化第一代城市走法 vector<CityWalkMethod> vecCityWalkMethod; for(int i =0;i < UNIT_NUMBER;++i){ CityWalkMethod citywalkmethod; CITY_PATH cp = CreateRandomCitypath(); citywalkmethod.cityPath_ = cp; vecCityWalkMethod.push_back(citywalkmethod); } CalMethodPrice(vecCityWalkMethod); int loop = 0; while(loop < 1000) { SelectAndCrossOver(vecCityWalkMethod); DebugPrintVecCitymethod(vecCityWalkMethod); loop++; } cout << "Hello World!" << endl; return 0; }
1 #ifndef CITY_H 2 #define CITY_H 3 4 #include <vector> 5 #include <string> 6 7 using namespace std; 8 9 10 11 struct City{ 12 float x_; 13 float y_; 14 string cityName_; 15 City(){} 16 City(string name,float x,float y): 17 x_(x),y_(y),cityName_(name) {} 18 }; 19 20 #define CITY_PATH vector<int> 21 22 struct CityWalkMethod{ 23 CITY_PATH cityPath_; 24 double distance_; 25 double pathPrice_; 26 CityWalkMethod():distance_(0),pathPrice_(0){} 27 bool operator ==(const CityWalkMethod& r){ 28 return cityPath_ == r.cityPath_; 29 } 30 }; 31 32 #endif // CITY_H
代码中 我们使用
void InitListCity(){
vecCityList.push_back(City("1",1.0,2.0));
vecCityList.push_back(City("2",3.0,2.0));
vecCityList.push_back(City("3",5.0,2.0));
vecCityList.push_back(City("4",1.0,3.0));
vecCityList.push_back(City("5",2.0,3.0));
vecCityList.push_back(City("6",4.0,3.0));
vecCityList.push_back(City("7",5.0,3.0));
vecCityList.push_back(City("8",1.0,4.0));
vecCityList.push_back(City("9",3.0,4.0));
vecCityList.push_back(City("0",5.0,4.0));
}
来将城市信息输入
城市信息结构为
float x y 城市坐标
string name 城市名称
而城市的走法 我们使用的是是整数数组 记录依次走过城市的走法
比如 城市走法数组为 2 1 0 3 则代表我们走过城市的走法为
先走过vecCityList中第三个城市(vecCityList[2])
再走到vecCityList中第二个城市(vecCityList[1])
再走到vecCityList中第一个城市(vecCityList[0])
再走到vecCityList中第四个城市(vecCityList[3])
每种城市走法的评分标准是 将每种走法中最长的距离得出 依次将走法的距离同最长距离相减 就是该走法的评价得分
每种城市走法的距离计算方式是 第一个城市X Y 同第二个城市的 X Y的平方差开根号 (distance)² = (x₁-x₂)² - (y₁-y₂)²
各个城市之间的距离综合就是城市走法的距离
有了走法 有了评分标准 然后就是遗传算法的三板斧
选择 交叉 变异
选择办法为 首先选择得分最高的几条 直接放入下一代中保证优良基因的延续
代码
// 按照走法评分排序 选择得分最高 直接放入下一代中保证优良基因的延续
sort(vecCityWalkMethod.begin(),vecCityWalkMethod.end(),CompareMethodPrice);
for(int i =0;i < HOLD_UNIT_NUMBER;i++){
//上一代最优走法 优先保留到下一代
tmp.push_back(vecCityWalkMethod[i]);
}
然后在总分区间总 生成一个随机数 随机数在那种方法的区间里 就选择它
CityWalkMethod SelectMethodUnit(vector<CityWalkMethod>& vecCityWalkMethod){
double totalPrice = 0.0;
for(int i = 0 ;i < vecCityWalkMethod.size();++i){
totalPrice += vecCityWalkMethod[i].pathPrice_;
}
double slice = RandFloat()*totalPrice;
totalPrice = 0.0;
int index = 0;
for(int i = 0;i < vecCityWalkMethod.size();++i){
totalPrice += vecCityWalkMethod[i].pathPrice_;
if(totalPrice > slice){
index = i;
break;
}
}
return vecCityWalkMethod[index];
}
交叉
代码
void CrossOver(const CityWalkMethod& methodA,
const CityWalkMethod& methodB,
CityWalkMethod& baby1,
CityWalkMethod& baby2){
int beg = rand()% (methodA.cityPath_.size());
int end = rand()% (methodA.cityPath_.size());
while(beg == end){
end = rand()% (methodA.cityPath_.size());
}
if(end < beg){
swap(end,beg);
}
baby1 = methodA;
baby2 = methodB;
for(int pos = beg;pos<=end;++pos){
int indexA = methodA.cityPath_[pos];
int indexB = methodB.cityPath_[pos];
if(indexA != indexB){
vector<int>::iterator it1 = find(baby1.cityPath_.begin(),baby1.cityPath_.end(),indexA);
vector<int>::iterator it2 = find(baby1.cityPath_.begin(),baby1.cityPath_.end(),indexB);
swap(*it1,*it2);
it1 = find(baby2.cityPath_.begin(),baby2.cityPath_.end(),indexA);
it2 = find(baby2.cityPath_.begin(),baby2.cityPath_.end(),indexB);
swap(*it1,*it2);
}
}
}
变异
变异则简单很多 随机的变异概率 随机的选择行走方法中的索引 然后交换
比如行走方式 21304
随机一个数字 如果大于变异概率 比如 随机范围100 大于90则变异 则进行变异
在行走方式中 随机选择两个数字 比如选择了 1 和0
那么行走方式 21304 变异为 20314
反复多次 得到极其接近最优解的答案
以 代码为例
第一次随机生成的 行走路线
距离在27到19 之间
经过几代遗传后 结果如图
路线最短距离已经变成17了
经过100次遗传后 路线最短距离已经变成15了