zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Flex验证器 validate stringvalidate
    Flex4学习笔记 checkBox RadioButton DropDownList colorPicker
    Flex学习笔记PopUpMenuButton
    FLEX中一组基于button的组件
    flex学习笔记 显示数字步进
    flex学习笔记-日历选择与显示
    bar
    Flex的一些小实例
    最长公共子序列(LCS) Medium2
    最长公共子序列(LCS) Medium1
  • 原文地址:https://www.cnblogs.com/IThaitian/p/2750837.html
Copyright © 2011-2022 走看看