天气与日历 切换到窄版

 找回密码
 立即注册
中国膜结构网
十大进口膜材评选 十大国产膜材评选 十大膜结构设计评选 十大膜结构公司评选
查看: 76|回复: 0

基于精英选择策略的遗传算法

[复制链接]

该用户从未签到

主题

0

回帖

2912

积分

管理员

积分
2912
发表于 2024-6-22 09:46:18 | 显示全部楼层 |阅读模式
/*由Parrot改进的遗传算法求解TSP
*
*选择操作使用转赌轮算法
*变异算子采用逆转变异算法
*交叉时先使用顺序编码,单点交叉,然后解码
*/

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <cstdlib>
#include<unordered_map>
#include<utility>
#include <time.h>
#include <assert.h>
using namespace std;

unsigned int cityNum=20; //城市数目
double** dist;  //两两城市之间距离
const unsigned int generation = 5000;         //迭代次数
const unsigned int populationSize = 50;  //染色体数目
unsigned int chromLen = cityNum;   //单条染色体序列长度,在这里为城市数目cityNum

const double mutationRate = 0.07;  //基因突变概率
const double crossoverRate = 0.95;         //两条染色体交叉概率
const int select_chromPair = 30; //选择染色体交叉对的次数
//等级选择+轮盘赌算法
//无条件保留最优的5条解,其余的分成5个等级,选择rank[5,10)的概率为2%
//选择rank[10,20)的概率为10%, 选择rank[20,30)的概率为18%
//选择rank[30,40)的概率为30%,选择rank[40,50)的概率为40%
//每个等级内部则根据其适应函数按轮盘赌算法选择

//轮盘赌算法,用于等级算法的第二次选择
int roulette_select(const double *fitness,int p,int r)
{
        int i;
        double* stage=new double[r-p+1];
        stage[0] = fitness[p];
        for (i=1;i<r-p+1;i++){
                stage[i]=stage[i-1] + fitness[p+i];
        }
        double d = (rand()*1.0/RAND_MAX) * stage[r-p];
        i=0;
        while(d>stage[i]) i++;
        delete[] stage;
        return p+i;
}

int rank_select(const double* fitness,int sz)
{
        int i;
        //第一次选择等级区间
        int rand_num = rand()%100;
        if(rand_num<2) return roulette_select(fitness,5,9);
        if(rand_num<12) return roulette_select(fitness,10,19);
        if(rand_num<30) return roulette_select(fitness,20,29);
        if(rand_num<60) return roulette_select(fitness,30,39);
        return roulette_select(fitness,40,49);
}

//生成[0,n-1]的随机序列,保存到randorder中
void rand_int_order(vector<int>& randorder,const int n)   
{   
        assert(n>1);  

        randorder.clear();
        randorder.resize(n);
        vector<int> recoder;
        for (int i=0;i<n;i++){
                recoder.push_back(i);       
        }
        for(int i=0;i<n;i++){
                int sel=rand()%recoder.size();
                randorder[i]=recoder[sel];
                recoder.erase(recoder.begin()+sel);
        }
        //assertion
        assert(randorder.size()==n);
}

//编码函数
void sequence_encode(vector<int>& chromosome)
{
        vector<int> standard;
        for (int i=0;i<chromosome.size();i++){
                standard.push_back(i);
        }
        vector<int>::iterator ite;
        for (int i=0;i<chromosome.size();i++){
                ite=find(standard.begin(),standard.end(),chromosome[i]);
                assert(ite!=standard.end());
                chromosome[i]=ite-standard.begin();
                standard.erase(ite);
        }

}
//解码函数
void sequence_decode(vector<int>& chromosome)
{
        vector<int>standard;
        for (int i=0;i<chromosome.size();i++){
                standard.push_back(i);
        }
        for (int i=0;i<chromosome.size();i++){       
                int t=chromosome[i];
                chromosome[i]=standard[t];
                standard.erase(standard.begin()+t);
        }

}

//计算可行路径的适应函数值
double caculate_fit(const vector<int> &path)
{
        double sum=0;
        for(int i=1;i<=chromLen;i++) sum+=dist[path[i-1]][path[i%chromLen]];
        return sum;
}

//初始化各城市之间的距离
void init(){
        fstream fin("input_data.txt",ios::in);
        dist=new double*[cityNum];
        for (int i=0;i<cityNum;i++)        dist[i]=new double[cityNum];
        int data;
        for (int i=0;i<cityNum;i++){               
                for (int j=i;j<cityNum;j++){
                        fin>>data;
                        if(i!=j) dist[i][j]=dist[j][i]=data;
                        else dist[i][j]=0;
                }
        }
        fin.close();
}

void run()
{       
        fstream fout("output.txt",ios::out);
        int curTime=int(time(0));

        srand((unsigned)time(NULL));

        // 染色体数组
        vector<vector<int> > population; //第0代

        //随机化染色体序列
        for (int i=0;i<populationSize;i++){
                vector<int> chromo;
                rand_int_order(chromo,chromLen); //随机产生一个可行解(用chromo表示)
                population.push_back(chromo);
        }

        double glob_best_len = INT_MAX;  //整个进化过程中得到的最优路径的长度
        vector<int> glob_best_path; //整个进化过程中得到的最优路径

        //开始进化
        for (int g=0;g<generation;g++){       
                double *fitness = new double[populationSize];        //适应函数(可行路径的长度)
                for(int i=0;i<populationSize;i++) fitness[i]=0;
                //计算当前每条染色体的适应度函数(路径的长度)
                for (int s=0;s<populationSize;s++) fitness[s]=caculate_fit(population[s]);
                       
                vector<vector<int> > parent;   //parent为population按适应函数插入排序后得到的染色体组
                for(int i=0;i<population.size();i++){
                        int j=0;  
                        while(j<parent.size() && fitness[i]>=fitness[j]) j++;  //插入位置
                        parent.insert(parent.begin()+j,population[i]);
                        double tmp = fitness[i];
                        for(int k=i;k>=j+1;k--) fitness[k]=fitness[k-1];    //同时更改fitness
                        fitness[j]=tmp;  
                }

                population.clear(); //清空population,用以保存下一轮染色体
                fout<<"**************************************************************************\n";
                fout<<"第 "<<g<<" 轮进化\n";
                for(int i=0;i<populationSize;i++){
                        fout<<"路径"<<i<<":"<<fitness[i]<<"(长度)\n";
                        for(int j=0;j<chromLen;j++) fout<<parent[i][j]<<"-->";
                        fout<<"\n\n";
                }
                fout<<"**************************************************************************\n";

                if(glob_best_len>fitness[0]){ glob_best_len=fitness[0]; glob_best_path = parent[0];}

                //选择25对交叉的染色体序号,去掉重复的
                unordered_map<int,int> tab;   //交叉对
                for(int i=0;i<select_chromPair;i++){
                        int rs1 = rank_select(fitness,populationSize-1),rs2=rs1;
                        while(rs2==rs1) rs2 = rank_select(fitness,populationSize-1);
                        if(tab.find(rs1)==tab.end() && tab.find(rs2)==tab.end()){
                                tab[rs1] = rs2; tab[rs2] = rs1;
                        }
                }
               
                //将当前代没有被选择作为交叉对的直接加入到下一代
                for(int i=0;i<populationSize;i++){
                        if(tab.find(i)==tab.end()){
                                vector<int> baby = parent[i];
                                if(rand()*1.0/RAND_MAX < mutationRate){ //进行变异
                                        int p1 = rand()%chromLen, p2 = p1;
                                        while(p1==p2) p2=rand()%chromLen;

                                        //逆转baby染色体的某一段
                                        reverse(baby.begin()+ min(p1,p2),baby.begin()+ max(p1,p2));
                                }
                                //精英策略,若是比当前代更差,则不保留baby
                                if(caculate_fit(baby)<fitness[i]) population.push_back(baby);
                                else population.push_back(parent[i]);
                               
                        }
                }
                //按交叉概率决定选出来的交叉对是否交叉
                while(population.size()<populationSize){

                        unordered_map<int,int>::iterator it = tab.begin();
                        int k1 = it->first, k2 = it->second;
                        vector<int> baby1 = parent[k1], baby2 = parent[k2];
                        tab.erase(k1);
                        tab.erase(k2);
                        if (rand()*1.0/RAND_MAX<crossoverRate){ //染色体交叉
                                //编码
                                sequence_encode(baby1);
                                sequence_encode(baby2);

                                //将编码后的两条染色体单点交叉
                                int crs = rand()%chromLen;
                                swap(baby1[crs],baby2[crs]);

                                //解码,解码后的染色体可能是连续交叉
                                sequence_decode(baby1);
                                sequence_decode(baby2);       
                        }

                        //根据变异概率让baby1,baby2变异
                        for(int b=0;b<=1;b++){
                                if(rand()*1.0/RAND_MAX < mutationRate){
                                        int p1 = rand()%chromLen, p2 = p1;
                                        while(p1==p2) p2=rand()%chromLen;

                                        //逆转baby1,baby2染色体的某一段
                                        if(b==0) reverse(baby1.begin()+ min(p1,p2),baby1.begin()+ max(p1,p2));
                                        else reverse(baby2.begin()+ min(p1,p2),baby2.begin()+ max(p1,p2));
                                }
                        }
                       
                        if(caculate_fit(baby1)<fitness[k1]) population.push_back(baby1);
                        else population.push_back(parent[k1]);
                        if(caculate_fit(baby2)<fitness[k2]) population.push_back(baby2);
                        else population.push_back(parent[k2]);       
                }       
                delete fitness;
        }

        fout<<"\n\n\n历史最优路径长度: "
                <<glob_best_len<<endl                       
                <<"历史最优路径:\n";
        for (int i=0;i<cityNum;i++){
                fout<<glob_best_path[i]<<" ";
        }
        fout<<endl;
        curTime=int(time(0))-curTime;
        fout<<"总共用时:"<<curTime<<"ms\n";
        fout.close();
}

int main(){
        cout<<"running..."<<endl;
        init();
        run();
        for (int i=0;i<cityNum;i++){ delete[] dist[i];}       
        delete[] dist;
        cout<<"done!"<<endl;
        return 0;
}

 

 

 

 

基于精英选择策略的遗传算法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|中国膜结构网|中国膜结构协会|进口膜材|国产膜材|ETFE|PVDF|PTFE|设计|施工|安装|车棚|看台|污水池|中国膜结构网_中国空间膜结构协会

GMT+8, 2024-11-1 10:24 , Processed in 0.109686 second(s), 24 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表