蚁群算法解决TSP问题(含详细注释+200行代码)

一、蚁群算法
蚁群算法是一种用来寻找优化路径的概率型算法。它由Marco Dorigo于1992年在他的博士论文中提出,其灵感来源于蚂蚁在寻找食物过程中发现路径的行为。这种算法具有分布计算、信息正反馈和启发式搜索的特征,本质上是进化算法中的一种启发式全局优化算法。将蚁群算法应用于解决优化问题的基本思路为:用蚂蚁的行走路径表示待优化问题的可行解,整个蚂蚁群体的所有路径构成待优化问题的解空间。路径较短的蚂蚁释放的信息素量较多,随着时间的推进,较短的路径上累积的信息素浓度逐渐增高,选择该路径的蚂蚁个数也愈来愈多。最终,整个蚂蚁会在正反馈的作用下集中到最佳的路径上,此时对应的便是待优化问题的最优解。

二、算法实现步骤(结合本题代码)

  1. 设置各种参数(迭代次数、蚁群数量、城市数量、信息素挥发速率等)
  2. 根据城市坐标点计算城市之间距离,并且初始化城市间路线上的信息素
  3. 判断迭代次数是否达到目标值,若达到目标值则跳出循环,输出当前路线长度最短的最佳路径,程序结束;否则进入步骤4
  4. 判断在某次迭代中,判断完成旅行的蚂蚁数量是否达到目标值,若达到目标值则结束当前迭代,并且迭代次数加1,更新最短路径和最短路径值,并且利用蚁环模型更新信息素,进入步骤3。否则进入步骤5
  5. 判断当前蚂蚁走过的城市数是否等于所有城市数,若完成旅行,则完成旅行的蚂蚁数量加1,进入步骤4。否则进入步骤6
  6. 计算蚂蚁从当前城市到所有未经过的下一个城市的概率,并通过轮盘算法进行选择下一个城市,则当前蚂蚁走过的城市数+1,修改禁忌表,进入步骤5

三、实现代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
using namespace std;
 
int CityPos[30][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}};

#define CITYNUM 20  //城市数量
#define ANTNUM 30   //蚁群数量
#define ITER 10   //迭代最大次数
#define R 0.5     //误差大小
#define ALPHA 1     // 信息素重要程度的参数
#define BETA 4     // 启发式因子重要程度的参数
#define Q 100 //信息素残留参数

const int maxn = 100;
double dis[maxn][maxn];        //距离


double info[maxn][maxn];  //信息素矩阵
int vis[CITYNUM][CITYNUM];
const double maxx = 10e9+10;

int random1(int l,int h){           //针对整数
    return l+(h-l)*rand()/(RAND_MAX+1);
}
 
double random2(double l,double h){          //针对浮点数
    double temp=rand()/((double)RAND_MAX+1.0);
    return l+temp*(h-l);
}

void city_init(){
        //计算两两城市间距离            可以考虑放在城市初始化中
        for (int i = 0; i < CITYNUM; i++){
            for (int j = 0; j < CITYNUM; j++){
                double temp1=CityPos[j][0]-CityPos[i][0];
                double temp2=CityPos[j][1]-CityPos[i][1];
                dis[i][j] = sqrt(temp1*temp1+temp2*temp2);
            }
        }

        //初始化环境信息素
        for (int i=0; i<CITYNUM; i++){
            for (int j=0; j<CITYNUM; j++){
                info[i][j]=1;             //线路上的信息素
            }
        }
}
 
class Ant{
    public:
    int path[CITYNUM];  //蚂蚁走的路径
    double length;  //路径总长度
    int vis[CITYNUM]; //走过城市标记
    int cur_pos;   //当前城市
    int arrived_city;    //到达的城市数量
    //初始化
   
    Ant(){}

    void init(){
        memset(vis, 0, sizeof(vis));
        length = 0;
        cur_pos = random1(0, CITYNUM);//随机选择一个出发城市
        path[0] = cur_pos;
        vis[cur_pos] = 1;
        arrived_city = 1;
    }

    //选择下一个要走的城市
    int NextCity(){
        int index=-1;       //下一个要走的城市的下标
        double sum_p=0;     //未经历过的城市的信息素的总和
        double p[CITYNUM];  //各个城市被选中的概率

        for(int i = 0; i < CITYNUM; i++){
            if (!vis[i]){
                p[i]=pow(info[cur_pos][i],ALPHA)*pow(1.0/dis[cur_pos][i], BETA);
                sum_p += p[i];          //计算当前点到未访问城市点的路线的的总信息素
            }   
        }

        for(int i = 0; i < CITYNUM; i++){
            if (!vis[i]){       //计算未被访问的城市被选中做下一个访问城市的概率
                p[i]/=sum_p;
            }
            else    p[i] = 0;             //代表已经被访问,因此被选中的概率为0
        }

        //进行轮盘赌法选择下一个城市
        double temp=0;  //总的信息素值大于0
        if (sum_p > 0){
            temp = random2(0,1);
            for (int i = 0; i < CITYNUM; i++){
                if (!vis[i]){
                    temp -= p[i];
                    if (temp < 0){          //代表当前城市被选中
                        index = i;
                        break;
                    }
                }
            }
        }

        if (index == -1){       //若轮盘赌法不成功,则选择编号最小的未去过的城市作为下一个目标
            for (int i=0; i<CITYNUM; i++){
                if (!vis[i]){   //城市没去过
                    index=i;    
                    break;
                }
            }
        }
        return index;
    }
 
    //蚂蚁在城市间移动
    void move(){
        int city_index = NextCity();//选择下一个城市
        path[arrived_city] = city_index;//保存蚂蚁走的路径
        vis[city_index] = 1;//把这个城市设置成已经去过
        cur_pos = city_index;//更新当前位置
        length += dis[path[arrived_city-1]][path[arrived_city]];
        arrived_city++;
    }

    void start(){        //蚂蚁开始出发完成一次环线
        init();
        while(arrived_city < CITYNUM){  //移动数小于所有城市数时则一直移动
            move();
        }
        length += dis[path[CITYNUM-1]][path[0]];
    }
};
 
 
class TSP{
    public:
    Ant ant[ANTNUM];  //定义一群蚂蚁
    Ant target;       //保存最好结果的蚂蚁
 
    TSP(){
        target.length = maxx;  //初始化为最大值
    }

    //进行信息素的更新
    void update()
    {
        double addInfo[CITYNUM][CITYNUM];
        memset(addInfo, 0, sizeof(addInfo));
        int m = 0;
        int n = 0;
        
        //遍历每只蚂蚁,更新路线信息素
        for (int i = 0; i <ANTNUM; i++) {      
            for (int j = 1; j < CITYNUM; j++){
                m = ant[i].path[j];
                n = ant[i].path[j-1];
                addInfo[n][m] = addInfo[n][m]+Q/ant[i].length;     //使用的是蚁环模型来增加信息素
                addInfo[m][n] = addInfo[n][m];
            }

            //更新起始和结束城市间路线的信息素
            n = ant[i].path[0];
            addInfo[n][m] = addInfo[n][m]+Q/ant[i].length;
            addInfo[m][n] = addInfo[n][m];
        }
 
        //更新总体环境信息素
        for (int i = 0; i < CITYNUM; i++){
            for (int j = 0; j < CITYNUM; j++) {
                info[i][j] = info[i][j]*R + addInfo[i][j]; //R为信息素挥发速率
            }
        }
    }

    void start(){   //TSP问题的开始
        for (int i = 0; i < ITER; i++) {     //蚁群需要的迭代次数
            // printf("current iteration times %d\n", i);
            cout<<"current iteration times :"<<i<<endl;
            for (int j = 0; j <ANTNUM; j++) {   //对于每只蚂蚁开始移动
                ant[j].start();
                cout<<"ant "<<j<<" path:";
                for(int k=0;k<CITYNUM;k++){    //把每个蚂蚁的路径打印出来
                    cout<<ant[j].path[k]<<" ";
                }
                cout<<endl;
            }

            for (int j = 0; j <ANTNUM; j++) {
                if (target.length > ant[j].length) {
                    target = ant[j];         //不断更新最佳结果
                }
            }
 
            update();   //每一次蚁群完成环线后进行信息素的更新
            printf("the shortest length %lf", target.length);
            cout<<" in iteration "<<i<<endl;

            cout<<"The best path in iteration"<<i<<": ";
            for (int i = 0; i < CITYNUM; i++) {
                cout<<target.path[i]<<" ";
            }
            cout<<endl<<endl<<endl;
        }
    }
};
 
 
int main(){
    srand((unsigned)time(NULL));
    city_init();
    TSP tsp;
    tsp.start();

    cout<<"The final route:"<<endl;
    for (int i = 0; i < CITYNUM; i++) {
        cout<<tsp.target.path[i]<<" ";
    }
    return 0;
}
  • 4
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值