zoukankan      html  css  js  c++  java
  • 遗传算法 旅行商问题为例

    #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了

     
    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    Writing an XMLRPC server or client in ASP.Net: Part 1
    a article test
    基于Android的一个简单多媒体播放器
    一涉及多个知识点的小测试程序
    Android蓝牙测试—发送一文件到另一蓝牙设备
    Android开发入门精品文章导引
    关于List对象的重复项清除和倒序处理
    关于Android的布局
    Android中对文本文件的读写处理
    Android系统中震动功能的测试
  • 原文地址:https://www.cnblogs.com/itdef/p/6831811.html
Copyright © 2011-2022 走看看