TSP问题_遗传算法(STL大量使用)

#include<iostream>
#include<vector>
#include<algorithm>//random_shuffle();sort();lower_bound();
#include<cmath>
#include<ctime>
using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
#define PB push_back //在vector尾部加入一个数据
#define MP make_pair //1.将2个数据组合成一个数据//2.当一个函数需要返回2个数据的时候,可以选择pair
//pair的实现是一个结构体,主要的两个成员变量是first、second 
//因为是使用struct不是class,所以可以直接使用pair的成员变量
int next_int();
double next_double();
void pmx(VI& a,VI& b,int pointcnt);//PMX交叉
double fitness(const VI& v,int pointcnt);//计算适应度
void change0(vector<int>& K,int N);//变异策略:两点互换
void mutate(VI& route,int mutate_type,int pointcnt);
bool pair_dec(const pair<double,VI*>& a,const pair<double,VI*>& b);
vector<double> x,y;//全局函数,记录城市坐标

class other_population
{
public:
    int popsize,pointcnt;//种群规模,染色体长度
    double pc,pm;//交叉概率,变异概率
    vector<pair<double,VI*> >pop;//种群
    pair<double,VI*> bestofpop;//最好个体
    int cross_type;//交叉类型
    int mutate_type;//变异类型
    int make_p;//个体概率分配策略类型
    int select_type;//个体选择类型
    int toursize;//竞赛规模
    double bestp;//最好个体选择概率
    other_population(int a,int b,int c,int f,int g,double d,double e,int h,double j,int m)
    {
        popsize=a,pointcnt=b,cross_type=c,mutate_type=f,make_p=g,pc=d,pm=e,toursize=h,bestp=j,select_type=m;
        for(int i=0;i<popsize;i++)//初始化种群
        {
            VI* v=new VI(pointcnt);
            for(int j=0;j<pointcnt;j++)
                (*v)[j]=j;
            random_shuffle(v->begin(),v->end());
            pop.PB(MP(fitness(*v,pointcnt),v));
        }
        sort(pop.begin(),pop.end(),pair_dec);
        bestofpop.first=pop[0].first;//初始时最好个体的适应度
        bestofpop.second=new VI(*pop[0].second);//初始时最好个体的染色体
    }
    ~other_population()
    {
        for(int i=0;i<pop.size();i++)
            delete pop[i].second;
        delete bestofpop.second;
    }
    void next()//产生下一代种群
    {
        vector<double> ps(popsize);
        if(make_p==0) //按适应度比例分配个体的选择概率
        {
            double sum=0;
            for(int i=0;i<popsize;i++)
                sum+=pop[i].first;
            for(i=0;i<popsize;i++)
                ps[i]=pop[i].first/sum;
        }    
    
        if(select_type==0)//轮盘赌选择个体
        {
            vector<pair<double,VI*> > select_res;
            vector<double> addsum(popsize);
            for(int i=0;i<popsize-1;i++)//计算个体的累计概率
            {
                if(i==0)
                    addsum[i]=ps[0];
                else
                    addsum[i]=addsum[i-1]+ps[i];
            }
            addsum[popsize-1]=1.5;
            for(i=0;i<popsize;i++)
            {
                double rd=next_double();
                int r=lower_bound(addsum.begin(),addsum.end(),rd)-addsum.begin();
                //lower_bound()返回一个 iterator 它指向在[first,last)标记的有序序列中可以插入value,
                //而不会破坏容器顺序的第一个位置,而这个位置标记了一个大于等于value 的值。
                VI* v=new VI(*pop[r].second);
                select_res.PB(MP(fitness(*v,pointcnt),v));
            }
            for(i=0;i<popsize;i++)
                delete pop[i].second;
            pop=select_res;
            ////////////////////////////////
            /*cout<<"选择后共"<<pop.size()<<"个子染色体\n";
            for(i=0;i<pop.size();i++)
            {
                VI temp=*pop[i].second;
                for(int j=0;j<10;j++)
                    cout<<temp[j]<<" ";
                cout<<"\n";
            }*/
            //////////////////////////////
        }    
        int Count_cross=0;
        for(int cc=0;cc<popsize/2;cc++)//随机选择两个个体,然后进行交叉
        {
            int a=next_int()%popsize;
            int b=(a+1+(next_int()%(popsize-1)))%popsize;
            if(next_double()<pc)//随机数小于交叉概率,进行交叉
            {
                if(cross_type==0)//pmx交叉
                    pmx(*pop[a].second,*pop[b].second,pointcnt);                
                ///////////////////////////////
                /*Count_cross+=2;
                cout<<"交叉后第"<< a <<"条子染色体: ";
                VI temp=*pop[a].second;
                for(int j=0;j<10;j++)
                    cout<<temp[j]<<" ";
                cout<<"\n";
                //////////////////////////////
                cout<<"交叉后第"<< b <<"条子染色体: ";
                temp=*pop[b].second;
                for(j=0;j<10;j++)
                    cout<<temp[j]<<" ";
                cout<<"\n";*/
                ////////////////////////////////

                pop[a].first=fitness(*pop[a].second,pointcnt);//计算交叉后个体a的适应度
                if(bestofpop.first<pop[a].first)//更新最好个体
                {
                    bestofpop.first=pop[a].first;
                    delete bestofpop.second;
                    bestofpop.second=new VI(*pop[a].second);
                }
                pop[b].first=fitness(*pop[b].second,pointcnt);//计算交叉后个体b的适应度
                if(bestofpop.first<pop[b].first)//更新最好个体
                {
                    bestofpop.first=pop[b].first;
                    delete bestofpop.second;
                    bestofpop.second=new VI(*pop[b].second);
                }
            }        
        }
        //////////////////////////////////////
        //cout<<"交叉"<<Count_cross<<"条染色体\n";
        //cout<<"交叉后共"<<pop.size()<<"个子染色体\n";        
        /////////////////////////////////////

        int Count_mutate=0;//变异染色体条数
        for(int i=pop.size()-1;i>=0;i--)//进行变异
            if(next_double()<pm)//随机数小于变异概率,进行变异
            {
                mutate(*pop[i].second,mutate_type,pointcnt);//变异
                pop[i].first=fitness(*pop[i].second,pointcnt);//计算变异后个体的适应度
                ///////////////////////////////
                /*Count_mutate++;
                cout<<"变异后第"<< i <<"个子染色体: ";
                VI temp=*pop[i].second;
                for(int j=0;j<10;j++)
                    cout<<temp[j]<<" ";
                cout<<"\n";*/
                ///////////////////////////////
            }
        ///////////////////////////////
        //cout<<"变异"<<Count_mutate<<"条染色体\n";
        //cout<<"变异后共"<<pop.size()<<"个子染色体\n\n\n";    
        ///////////////////////////////

        sort(pop.begin(),pop.end(),pair_dec);//从大到小排序
        if(bestofpop.first<pop[0].first)//更新最好个体
        {
            delete bestofpop.second;
            bestofpop.first=pop[0].first;
            bestofpop.second=new VI(*pop[0].second);
        }
    }
};
int next_int()
{
    return rand()*(RAND_MAX+1)+rand();
}
double next_double()
{
    return (double(rand()*(RAND_MAX+1)+rand()))/((RAND_MAX+1)*RAND_MAX+RAND_MAX);
}
double fitness(const VI& v,int pointcnt)//计算适应度
{
    double r=0;
    for(int i=0;i<pointcnt;i++)
    {
        double dx=x[v[i]]-x[v[(i+1)%pointcnt]];
        double dy=y[v[i]]-y[v[(i+1)%pointcnt]];
        r+=sqrt(dx*dx+dy*dy);//个体的适应度为相邻两城市之间的距离平方的平方根和
    }
    return 1.0/r;
}
int flag=0;
void pmx(VI& a,VI& b,int pointcnt)//PMX交叉
{
    
    int i;
    int sa=next_int()%pointcnt,sb=next_int()%pointcnt;//随机选择两交叉位
    if (sa>sb)
    {        
        swap(sa,sb);
    }//保证交叉位sa<=sb
    
    /*if(flag==0)
    {
        cout<<"互换前(互换位:"<<sa<<" "<<sb<<")\n";
        for(i=0;i<10;i++)
            cout<<a[i]<<" ";
        cout<<"\n";
        for(i=0;i<10;i++)
            cout<<b[i]<<" ";
        cout<<"\n";    
    }*/
    VI m1(pointcnt,-1);
    VI m2(pointcnt,-1);    
    for (i = sa; i <= sb; ++i) //互换交叉位之间的基因
    {
        //相当于a中将城市a[i]删了,用城市b[i]取代,从而出现城市b[i](替换后的a'[i])重复
        //        b中将城市b[i]删了,用城市a[i]取代,从而出现城市a[i](替换后的b'[i])重复
        swap(a[i], b[i]);    
        m1[a[i]] = b[i];//记录a'[i]所取代的城市a[i],用于替换非交叉部分的a'[i]的元素重复
        m2[b[i]] = a[i];
    }
    ///////////////////////
    /*if(flag==0)
    {
        cout<<"互换后(未调整)\n";
        for(i=0;i<10;i++)
            cout<<a[i]<<" ";
        cout<<"\n";
        for(i=0;i<10;i++)
            cout<<b[i]<<" ";
        cout<<"\n";

        for(i=0;i<10;i++)
            cout<<m1[i]<<" ";
        cout<<"\n";
        for(i=0;i<10;i++)
            cout<<m2[i]<<" ";
        cout<<"\n";
    }*/
    ///////////////////////
    for (i = 0; i < pointcnt; ++i)//调整交叉位之前、之后的基因,防止和交叉位之间的基因重复
        if (i < sa || i > sb) 
        {
                if (m2[b[i]] != -1) 
                {
                    while (m2[b[i]] != -1)
                        b[i] = m2[b[i]];
                }    
                if (m1[a[i]] != -1) 
                {
                    while (m1[a[i]] != -1)
                       a[i] = m1[a[i]];
                }        
        }
    /////////////////////
    /*if(flag==0)
    {
        cout<<"互换调整后\n";
        for(i=0;i<10;i++)
            cout<<a[i]<<" ";
        cout<<"\n";
        for(i=0;i<10;i++)
            cout<<b[i]<<" ";
        cout<<"\n";
    }
    flag=1;*/
    ////////////////////
}
void mutate(VI& route,int mutate_type,int pointcnt)//变异
{
    if(mutate_type==0)//两点互换
        change0(route,pointcnt);    
}
void change0(vector<int>& K,int N)//变异策略:两点互换
{
    int i=next_int()%N;
    int d=next_int()%(N-1);
    int j=(i+1+d)%N;
    swap(K[i],K[j]);
}
bool pair_dec(const pair<double,VI*>& a,const pair<double,VI*>& b)//比较因子,用于sort()函数
{
    return a>b;
}






int main()
{
    srand((unsigned)time(NULL));
    int CASNUM,POINTCNT,POPSIZE,GENERATIONS;
    //scanf("%d",&CASNUM);
    CASNUM=10;//实验次数
    //scanf("%d%d%d",&POINTCNT,&POPSIZE,&GENERATIONS);
    POINTCNT=10, POPSIZE=100,GENERATIONS=100;//染色体长度(城市数),种群规模,最大迭代步数
    cout<<"城市数="<<POINTCNT<<endl;
    x.resize(POINTCNT);
    y.resize(POINTCNT);
    x[0]=87, x[1]=91,x[2]=83,x[3]=71,x[4]=64,x[5]=68,x[6]=83,x[7]=87,x[8]=74,x[9]=71;
    y[0]=7,  y[1]=38,y[2]=46,y[3]=44,y[4]=60,y[5]=58,y[6]=69,y[7]=76,y[8]=78,y[9]=71;    
    cout<<"各城市坐标:"<<endl;
    for(int i=0;i<POINTCNT;i++)
    {
        //scanf("%lf%lf",&x[i],&y[i]);//输入各个城市的坐标
        cout<<"["<<x[i]<<", "<<y[i]<<"]"<<endl;//输出各个城市的坐标                
    }    

    int select_type,make_p_type,k,cross_type,mutate_type;
    double q,pc,pm;
    //scanf("%d%d%d",&select_type,&make_p_type,&k);
    //scanf("%lf%lf%lf",&q,&pc,&pm);
    //scanf("%d%d",&cross_type,&mutate_type);
    select_type=0,make_p_type=0,k=5;//个体选择方法类型,个体选择概率分配类型,竞赛规模
    q=0.5,pc=0.85,pm=0.15;//最好个体选择概率,交叉概率,变异概率
    cross_type=0,mutate_type=0;//交叉类型,变异类型
    
    double best=1e9,worst=0,sum=0;
    VI res;
    for(int cas=0;cas<CASNUM;cas++)//进行10代的试验
    {
        other_population gen(POPSIZE,POINTCNT,cross_type,mutate_type,make_p_type,pc,pm,k,q,select_type);//初始化
        for(int g=0;g<GENERATIONS;g++)//每次试验进行迭代进化(100代进化)
            gen.next();//每代进化过程中都会记录最更好的染色体
        if(best>1.0/gen.bestofpop.first)//更新历次最好适应度
        {
            best=1.0/gen.bestofpop.first;
            res=*gen.bestofpop.second;//存放最好个体的染色体
        }
        if(worst<1.0/gen.bestofpop.first)//更新历次最差适应度
            worst=1.0/gen.bestofpop.first;
        sum+=1.0/gen.bestofpop.first;//计算各次最好个体的适应度之和
    }
    sum/=CASNUM;//计算平均适应度
    cout<<endl;
    cout<<"历次最好适应度:"<<best<<"\n"<<"历次最差适应度:"<<worst<<"\n"<<"平均适应度:"<<sum<<"\n";
    cout<<"输出最好解:";
    for(i=0;i<POINTCNT;i++)//输出解
    {
        cout<<res[i];//输出各城市
        if (i<POINTCNT-1)
            cout<<"-";
    }
    cout<<endl;

    return 0;
}
原文地址:https://www.cnblogs.com/IThaitian/p/2750837.html