zoukankan      html  css  js  c++  java
  • 蚁群算法求解tsp

    先来说一下整个蚁群算法的思想:模拟蚂蚁寻找食物的过程。每只蚂蚁觅食时在走过的路线上会留下一种称为信息素的物质,蚂蚁之间靠感知这种物质的浓度进行信息传递。蚂蚁在选择路径时总是倾向于朝信息索浓度高的方向移动,而距离短的路径上走过的蚂蚁多,留下的信息素也多,后续蚂蚁选择它的概率也会越大;其他路径上的信息素会随着时间的推移不断挥发,这样就形成了一种正反馈机制,最后整个蚁群聚集到最短路径上。

    我个人感觉这个算法比较重要的两个点:(1)如何选择先一步要走的城市。这个选择里面有两个值起作用,一个是当前位置到下一个城市的距离,另一个是这条路上的信息素的浓度。有两个值ALPHA和BETA分别调节他们的权重,(怎么设置好像得靠经验了)。

    2)就是信息素的更新方式。代码里采用蚁量算法更新信息素即:

     

    就是释放的信息素除ij的距离。(为什么这么设置原因很简单,路径越长信息素就越少)。

    最后就是通过新信息素=信息素残留系数*原来的信息素+增加的信息素的方式完成更新。其他的都是比较简单的了。

    具体看代码吧!

    #include <bits/stdc++.h>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<iostream>
    //#define NULL -1
    typedef long long ll;
    using namespace std;
    double INF = 10e9;
    const int num_ant=30;//蚂蚁的数量
    const int num_city=30;//城市数量
    const int MAX_GEN=1000;//最大迭代次数
    int ALPHA = 1;//信息素的权重
    int BETA = 4;//启发式因子重要程度权重
    int remain = 100;//信息素残留参数
    //double beat_path;//最优路径长度
    double dis[num_city+50][num_city+50];//各个城市的距离
    int city[num_city][2]={{87,7},{91,38},{83,46},{71,44},{64,60},{68,58},{83,69},{87,76},{74,78},{71,71},{58,69},{54,62},{51,67},{37,84},{41,94},{2,99},{7,64},{22,60},{25,62},{18,54},{4,50},{13,40},{18,40},{24,42},{25,38},{41,26},{45,21},{44,35},{58,35},{62,32}};
    //各个城市的位置
    int vis[num_city][num_city];//禁忌表
    double info[num_city][num_city];//信息素矩阵
    //double active[num_city][num_city];//启发因子矩阵
    const int Q = 100;//信息素残留系数
    double ROU = 0.5;//信息素残留度
    unsigned seed=(unsigned)time(0);
    int random (int l,int h)
    {
        return l+(h-l)*rand()/(RAND_MAX+1);
    }
    double random(double l,double h)
    {
        return l+(h-l)*rand()/(RAND_MAX+1.0);
    }
    double Random (double ans)
    {
        return (double)((int)(ans+0.5));
    }
    double power(double x, int y)//快速幂
    {
        double ans = 1;
        while(y)
        {
            if(y&1)ans*=x;
            x*=x;
            y>>=1;
        }
        return ans;
    }
    struct Ant
    {
        int Path[num_city];
        double length;//当前已走的长度;
        int vis[num_city];//已走的城市
        int cur_city;//现在所在的城市
        int num_move;//已经走的城市数
        void Init()
        {
            memset(vis,0,sizeof(vis));
            length=0.0;
            cur_city=random(0,num_city);
            Path[0]=cur_city;
            vis[cur_city]=1;
            num_move=1;
        }
        int choose()
        {
            int select_city=-1;//选择的城市
            double sum=0.0;
            double possible_city[num_city];//各个城市被选中的概率
            for(int i=0;i<num_city;i++)
            {
                if(!vis[i])
                {
                    possible_city[i]=power(info[cur_city][i],ALPHA)*power(1.0/dis[cur_city][i],BETA);
                    sum+=possible_city[i];//计算概率
                }
                else
                {
                    possible_city[i]=0;
                }
            }
            //轮盘赌选择
            double possible_du=0.0;
            //double sum_tmp=0.0;
            if(sum>0.0)
            {
                possible_du=random(0.0,sum);
                for(int i=0;i<num_city;i++)
                {
                    if(!vis[i])
                    {
                        possible_du-=possible_city[i];
                        if(possible_du<0.0)
                        {
                            select_city=i;
                            break;
                        }
                    }
                }
            }
            if(select_city==-1)
            {
                for(int i=0;i<num_city;i++)
                {
                    if(!vis[i])
                    {
                        select_city=i;
                        break;
                    }
                }
            }
            return select_city;
        }
        void move_ant()
        {
            //if(num_move>=30)printf("KKKKKKK");
            int next_city=choose();//选择的城市
            Path[num_move]=next_city;
            vis[next_city]=1;
            cur_city=next_city;//更新当前位置
            length+=dis[Path[num_move-1]][Path[num_move]];
            num_move++;
            //if(num_move>=30)printf("KKKKKKK");
        }
        void find_()
        {
            Init();
            while(num_move<num_city)
            {
                move_ant();
                //printf("%d ",num_move);
                //printf("?????");
            }
            //printf("???");
            length+=dis[Path[num_city-1]][Path[0]];//更新长度
            //printf("??");
        }
    };
    struct TSP
    {
        Ant ants[num_ant];
        Ant ant_best;
        void Init()
        {
            ant_best.length=double(INF);//初始化最优的蚂蚁,设为最大
            printf("Begin to count
    ");
            for(int i=0;i<num_city;i++)
            {
                for(int j=0;j<num_city;j++)
                {
                    double tmp1=city[j][0]-city[i][0];
                    double tmp2=city[j][1]-city[i][1];
                    dis[i][j]=sqrt(tmp1*tmp1+tmp2*tmp2);//计算每个城市间的距离
                    //printf("%d %d %lf
    ",i,j,dis[i][j]);
                }
            }
            printf("Init Information
    ");
            for(int i=0;i<num_city;i++)
            {
                for(int j=0;j<num_city;j++)
                {
                    info[i][j]=1.0;//初始化信息素
                }
            }
        }
        void Update()
        {
            double tmpinfo[num_city][num_city];//临时矩阵储存新增的信息素
            memset(tmpinfo,0,sizeof(tmpinfo));
            int n=0;
            int m=0;
            //蚁量算法更新信息素
            for(int i=0;i<num_ant;i++)
            {
                for(int j=1;j<num_city;j++)
                {
                    n=ants[i].Path[j-1];
                    m=ants[i].Path[j];
                    tmpinfo[n][m]+=Q/ants[i].length;
                    tmpinfo[m][n]=tmpinfo[n][m];
                }
                n=ants[i].Path[0];
                tmpinfo[n][m]+=Q/ants[i].length;
                tmpinfo[m][n]=tmpinfo[n][m];
            }
            //更新环境的信息素
            for(int i=0;i<num_city;i++)
            {
                for(int j=0;j<num_city;j++)
                {
                    //新环境的信息素=残留的+新留下的
                    info[i][j]=info[i][j]*ROU+tmpinfo[i][j];//感觉ROU有待商榷
                }
            }
        }
    
        void find_()
        {
            for(int i=0;i<MAX_GEN;i++)
            {
                printf("current generation is %d
    ",i);
                for(int j=0;j<num_ant;j++)
                {
                    ants[j].find_();
                    //printf("****");
                }
                for(int j=0;j<num_ant;j++)
                {
                    if(ant_best.length>ants[j].length)
                    {
                        ant_best=ants[j];//更新每一代的最优解
                    }
                }
                Update();
                printf("current best length is %lf
    ",ant_best.length);
            }
        }
    };
    int main()
    {
        srand(seed);//随机函数初始化
        TSP tsp;
    //    printf("Please enter 30 cities position
    ");
    //    for(int i=0;i<30;i++)
    //    {
    //        scanf("%d%d",&city[i][0],&city[i][1]);//可以自己手动输入城市位置
    //    }
        tsp.Init();
        tsp.find_();
        printf("The minimum path is 
    ");
        for(int i=0;i<num_city;i++)
        {
            printf("%d ",tsp.ant_best.Path[i]);//打印出路径
        }
        return 0;
    }
  • 相关阅读:
    CEF3研究(三)
    [你必须知道的.NET]第二十一回:认识全面的null
    [你必须知道的.NET]第二十回:学习方法论
    [你必须知道的.NET]第十九回:对象创建始末(下)
    [你必须知道的.NET]第十八回:对象创建始末(上)
    [你必须知道的.NET]第十七回:貌合神离:覆写和重载
    纯js的N级联动列表框 —— 基于jQuery
    基于存储过程的MVC开源分页控件
    【程序7】统计出所输入字符中英文字母、空格、数字和其它字符的个数
    【程序6】 求最大公约数和最小公倍数
  • 原文地址:https://www.cnblogs.com/kayiko/p/12049296.html
Copyright © 2011-2022 走看看