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;

}

你可能感兴趣的:(STL)