蚁群算法求解TSP问题的源代码

蚁群算法求解TSP问题的源代码

分类: 智能算法
2014-05-07 17:25 
524人阅读 
评论(1) 
收藏 
举报
蚁群算法 TSP win32程序设计

旅行商问题大都是用遗传算法求解,不过蚁群算法比它高效得多,在百度的蚁群算法吧里有人发了个注释清晰的代码,有兴趣的可以去研究一下蚁群算法和模拟退火算法,这两者都可以解决旅行商问题。而关于遗传算法和模拟退火算法,博客园里的某位牛人很清楚地介绍了,发个链接吧

遗传算法入门:http://www.cnblogs.com/heaad/archive/2010/12/23/1914725.html

模拟退火算法入门:http://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html

下面给出蚁群算法的源代码:

[cpp] 
view plain
copy
《蚁群算法求解TSP问题的源代码》
《蚁群算法求解TSP问题的源代码》

  1. // AO.cpp : 定义控制台应用程序的入口点。  
  2. #pragma once  
  3.   
  4. #include <iostream>  
  5. #include <math.h>  
  6. #include <time.h>  
  7.   
  8. const double ALPHA=1.0; //启发因子,信息素的重要程度  
  9. const double BETA=2.0;   //期望因子,城市间距离的重要程度  
  10. const double ROU=0.5; //信息素残留参数  
  11.   
  12. const int N_ANT_COUNT=34; //蚂蚁数量  
  13. const int N_IT_COUNT=1000; //迭代次数  
  14. const int N_CITY_COUNT=51; //城市数量  
  15.   
  16. const double DBQ=100.0; //总的信息素  
  17. const double DB_MAX=10e9; //一个标志数,10的9次方  
  18.   
  19. double g_Trial[N_CITY_COUNT][N_CITY_COUNT]; //两两城市间信息素,就是环境信息素  
  20. double g_Distance[N_CITY_COUNT][N_CITY_COUNT]; //两两城市间距离  
  21.   
  22. //eil51.tsp城市坐标数据  
  23. double x_Ary[N_CITY_COUNT]=  
  24. {  
  25.     37,49,52,20,40,21,17,31,52,51,  
  26.     42,31,5,12,36,52,27,17,13,57,  
  27.     62,42,16,8,7,27,30,43,58,58,  
  28.     37,38,46,61,62,63,32,45,59,5,  
  29.     10,21,5,30,39,32,25,25,48,56,  
  30.     30  
  31. };  
  32.   
  33. double y_Ary[N_CITY_COUNT]=  
  34. {  
  35.     52,49,64,26,30,47,63,62,33,21,  
  36.     41,32,25,42,16,41,23,33,13,58,  
  37.     42,57,57,52,38,68,48,67,48,27,  
  38.     69,46,10,33,63,69,22,35,15,6,  
  39.     17,10,64,15,10,39,32,55,28,37,  
  40.     40  
  41. };  
  42.   
  43. //返回指定范围内的随机整数  
  44. int rnd(int nLow,int nUpper)  
  45. {  
  46.     return nLow+(nUpper-nLow)*rand()/(RAND_MAX+1);  
  47. }  
  48.   
  49. //返回指定范围内的随机浮点数  
  50. double rnd(double dbLow,double dbUpper)  
  51. {  
  52.     double dbTemp=rand()/((double)RAND_MAX+1.0);  
  53.     return dbLow+dbTemp*(dbUpper-dbLow);  
  54. }  
  55.   
  56. //返回浮点数四舍五入取整后的浮点数  
  57. double ROUND(double dbA)  
  58. {  
  59.     return (double)((int)(dbA+0.5));  
  60. }  
  61.   
  62. //定义蚂蚁类  
  63. class CAnt  
  64. {  
  65. public:  
  66.     CAnt(void);  
  67.     ~CAnt(void);  
  68.   
  69. public:  
  70.   
  71.     int m_nPath[N_CITY_COUNT]; //蚂蚁走的路径  
  72.     double m_dbPathLength; //蚂蚁走过的路径长度  
  73.   
  74.     int m_nAllowedCity[N_CITY_COUNT]; //没去过的城市  
  75.     int m_nCurCityNo; //当前所在城市编号  
  76.     int m_nMovedCityCount; //已经去过的城市数量  
  77.   
  78. public:  
  79.   
  80.     int ChooseNextCity(); //选择下一个城市  
  81.     void Init(); //初始化  
  82.     void Move(); //蚂蚁在城市间移动  
  83.     void Search(); //搜索路径  
  84.     void CalPathLength(); //计算蚂蚁走过的路径长度  
  85.   
  86. };  
  87.   
  88. //构造函数  
  89. CAnt::CAnt(void)  
  90. {  
  91. }  
  92.   
  93. //析构函数  
  94. CAnt::~CAnt(void)  
  95. {  
  96. }  
  97.   
  98. //初始化函数,蚂蚁搜索前调用  
  99. void CAnt::Init()  
  100. {  
  101.   
  102.     for (int i=0;i<N_CITY_COUNT;i++)  
  103.     {  
  104.         m_nAllowedCity[i]=1; //设置全部城市为没有去过  
  105.         m_nPath[i]=0; //蚂蚁走的路径全部设置为0  
  106.     }  
  107.   
  108.     //蚂蚁走过的路径长度设置为0  
  109.     m_dbPathLength=0.0;  
  110.   
  111.     //随机选择一个出发城市  
  112.     m_nCurCityNo=rnd(0,N_CITY_COUNT);  
  113.   
  114.     //把出发城市保存入路径数组中  
  115.     m_nPath[0]=m_nCurCityNo;  
  116.   
  117.     //标识出发城市为已经去过了  
  118.     m_nAllowedCity[m_nCurCityNo]=0;  
  119.   
  120.     //已经去过的城市数量设置为1  
  121.     m_nMovedCityCount=1;  
  122.   
  123. }  
  124.   
  125. //选择下一个城市  
  126. //返回值 为城市编号  
  127. int CAnt::ChooseNextCity()  
  128. {  
  129.   
  130.     int nSelectedCity=-1; //返回结果,先暂时把其设置为-1  
  131.   
  132.     //==============================================================================  
  133.     //计算当前城市和没去过的城市之间的信息素总和  
  134.      
  135.     double dbTotal=0.0;     
  136.     double prob[N_CITY_COUNT]; //保存各个城市被选中的概率  
  137.   
  138.     for (int i=0;i<N_CITY_COUNT;i++)  
  139.     {  
  140.         if (m_nAllowedCity[i] == 1) //城市没去过  
  141.         {  
  142.             prob[i]=pow(g_Trial[m_nCurCityNo][i],ALPHA)*pow(1.0/g_Distance[m_nCurCityNo][i],BETA); //该城市和当前城市间的信息素  
  143.             dbTotal=dbTotal+prob[i]; //累加信息素,得到总和  
  144.         }  
  145.         else //如果城市去过了,则其被选中的概率值为0  
  146.         {  
  147.             prob[i]=0.0;  
  148.         }  
  149.     }  
  150.   
  151.     //==============================================================================  
  152.     //进行轮盘选择  
  153.     double dbTemp=0.0;  
  154.     if (dbTotal > 0.0) //总的信息素值大于0  
  155.     {  
  156.         dbTemp=rnd(0.0,dbTotal); //取一个随机数  
  157.   
  158.         for (int i=0;i<N_CITY_COUNT;i++)  
  159.         {  
  160.             if (m_nAllowedCity[i] == 1) //城市没去过  
  161.             {  
  162.                 dbTemp=dbTemp-prob[i]; //这个操作相当于转动轮盘,如果对轮盘选择不熟悉,仔细考虑一下  
  163.                 if (dbTemp < 0.0) //轮盘停止转动,记下城市编号,直接跳出循环  
  164.   
  165.    
  166.   
  167.  {  
  168.                     nSelectedCity=i;  
  169.                     break;  
  170.                 }  
  171.             }  
  172.         }  
  173.     }  
  174.   
  175.     //==============================================================================  
  176.     //如果城市间的信息素非常小 ( 小到比double能够表示的最小的数字还要小 )  
  177.     //那么由于浮点运算的误差原因,上面计算的概率总和可能为0  
  178.     //会出现经过上述操作,没有城市被选择出来  
  179.     //出现这种情况,就把第一个没去过的城市作为返回结果  
  180.      
  181.     //题外话:刚开始看的时候,下面这段代码困惑了我很长时间,想不通为何要有这段代码,后来才搞清楚。  
  182.     if (nSelectedCity == -1)  
  183.     {  
  184.         for (int i=0;i<N_CITY_COUNT;i++)  
  185.         {  
  186.             if (m_nAllowedCity[i] == 1) //城市没去过  
  187.             {  
  188.                 nSelectedCity=i;  
  189.                 break;  
  190.             }  
  191.         }  
  192.     }  
  193.   
  194.     //==============================================================================  
  195.     //返回结果,就是城市的编号  
  196.     return nSelectedCity;  
  197. }  
  198.   
  199.   
  200. //蚂蚁在城市间移动  
  201. void CAnt::Move()  
  202. {  
  203.     int nCityNo=ChooseNextCity(); //选择下一个城市  
  204.   
  205.     m_nPath[m_nMovedCityCount]=nCityNo; //保存蚂蚁走的路径  
  206.     m_nAllowedCity[nCityNo]=0;//把这个城市设置成已经去过了  
  207.     m_nCurCityNo=nCityNo; //改变当前所在城市为选择的城市  
  208.     m_nMovedCityCount++; //已经去过的城市数量加1  
  209. }  
  210.   
  211. //蚂蚁进行搜索一次  
  212. void CAnt::Search()  
  213. {  
  214.     Init(); //蚂蚁搜索前,先初始化  
  215.   
  216.     //如果蚂蚁去过的城市数量小于城市数量,就继续移动  
  217.     while (m_nMovedCityCount < N_CITY_COUNT)  
  218.     {  
  219.         Move();  
  220.     }  
  221.   
  222.     //完成搜索后计算走过的路径长度  
  223.     CalPathLength();  
  224. }  
  225.   
  226.   
  227. //计算蚂蚁走过的路径长度  
  228. void CAnt::CalPathLength()  
  229. {  
  230.   
  231.     m_dbPathLength=0.0; //先把路径长度置0  
  232.     int m=0;  
  233.     int n=0;  
  234.   
  235.     for (int i=1;i<N_CITY_COUNT;i++)  
  236.     {  
  237.         m=m_nPath[i];  
  238.         n=m_nPath[i-1];  
  239.         m_dbPathLength=m_dbPathLength+g_Distance[m][n];  
  240.     }  
  241.   
  242.     //加上从最后城市返回出发城市的距离  
  243.     n=m_nPath[0];  
  244.     m_dbPathLength=m_dbPathLength+g_Distance[m][n];     
  245.   
  246. }  
  247.   
  248.   
  249. //tsp类  
  250. class CTsp  
  251. {  
  252. public:  
  253.     CTsp(void);  
  254.     ~CTsp(void);  
  255.   
  256. public:  
  257.     CAnt m_cAntAry[N_ANT_COUNT]; //蚂蚁数组  
  258.     CAnt m_cBestAnt; //定义一个蚂蚁变量,用来保存搜索过程中的最优结果  
  259.                                         //该蚂蚁不参与搜索,只是用来保存最优结果  
  260.   
  261. public:  
  262.   
  263.     //初始化数据  
  264.     void InitData();  
  265.   
  266.     //开始搜索  
  267.     void Search();  
  268.   
  269.     //更新环境信息素  
  270.     void UpdateTrial();  
  271.   
  272.   
  273. };  
  274.   
  275.   
  276. //构造函数  
  277. CTsp::CTsp(void)  
  278. {  
  279. }  
  280.   
  281. CTsp::~CTsp(void)  
  282. {  
  283. }  
  284.   
  285.   
  286. //初始化数据  
  287. void CTsp::InitData()  
  288. {  
  289.   
  290.     //先把最优蚂蚁的路径长度设置成一个很大的值  
  291.     m_cBestAnt.m_dbPathLength=DB_MAX;  
  292.   
  293.     //计算两两城市间距离  
  294.     double dbTemp=0.0;  
  295.     for (int i=0;i<N_CITY_COUNT;i++)  
  296.     {  
  297.         for (int j=0;j<N_CITY_COUNT;j++)  
  298.         {  
  299.             dbTemp=(x_Ary[i]-x_Ary[j])*(x_Ary[i]-x_Ary[j])+(y_Ary[i]-y_Ary[j])*(y_Ary[i]-y_Ary[j]);  
  300.             dbTemp=pow(dbTemp,0.5);  
  301.             g_Distance[i][j]=ROUND(dbTemp);  
  302.         }  
  303.     }  
  304.   
  305.     //初始化环境信息素,先把城市间的信息素设置成一样  
  306.     //这里设置成1.0,设置成多少对结果影响不是太大,对算法收敛速度有些影响  
  307.     for (int i=0;i<N_CITY_COUNT;i++)  
  308.     {  
  309.         for (int j=0;j<N_CITY_COUNT;j++)  
  310.         {  
  311.             g_Trial[i][j]=1.0;  
  312.         }  
  313.     }  
  314.   
  315. }  
  316.   
  317.    
  318.   
  319.   
  320. //更新环境信息素  
  321. void CTsp::UpdateTrial()  
  322. {  
  323.     //临时数组,保存各只蚂蚁在两两城市间新留下的信息素  
  324.     double dbTempAry[N_CITY_COUNT][N_CITY_COUNT];  
  325.     memset(dbTempAry,0,sizeof(dbTempAry)); //先全部设置为0  
  326.   
  327.     //计算新增加的信息素,保存到临时数组里  
  328.     int m=0;  
  329.     int n=0;  
  330.     for (int i=0;i<N_ANT_COUNT;i++) //计算每只蚂蚁留下的信息素  
  331.     {  
  332.             for (int j=1;j<N_CITY_COUNT;j++)  
  333.             {  
  334.                 m=m_cAntAry[i].m_nPath[j];  
  335.                 n=m_cAntAry[i].m_nPath[j-1];  
  336.                 dbTempAry[n][m]=dbTempAry[n][m]+DBQ/m_cAntAry[i].m_dbPathLength;  
  337.                 dbTempAry[m][n]=dbTempAry[n][m];  
  338.             }  
  339.   
  340.             //最后城市和开始城市之间的信息素  
  341.             n=m_cAntAry[i].m_nPath[0];  
  342.             dbTempAry[n][m]=dbTempAry[n][m]+DBQ/m_cAntAry[i].m_dbPathLength;  
  343.             dbTempAry[m][n]=dbTempAry[n][m];  
  344.   
  345.     }  
  346.   
  347.     //==================================================================  
  348.     //更新环境信息素  
  349.     for (int i=0;i<N_CITY_COUNT;i++)  
  350.     {  
  351.         for (int j=0;j<N_CITY_COUNT;j++)  
  352.         {  
  353.             g_Trial[i][j]=g_Trial[i][j]*ROU+dbTempAry[i][j]; //最新的环境信息素 = 留存的信息素 + 新留下的信息素  
  354.         }  
  355.     }  
  356.   
  357. }  
  358.   
  359.   
  360. void CTsp::Search()  
  361. {  
  362.   
  363.     char cBuf[256]; //打印信息用  
  364.   
  365.     //在迭代次数内进行循环  
  366.     for (int i=0;i<N_IT_COUNT;i++)  
  367.     {  
  368.         //每只蚂蚁搜索一遍  
  369.         for (int j=0;j<N_ANT_COUNT;j++)  
  370.         {  
  371.             m_cAntAry[j].Search();  
  372.         }  
  373.   
  374.         //保存最佳结果  
  375.         for (int j=0;j<N_ANT_COUNT;j++)  
  376.         {  
  377.             if (m_cAntAry[j].m_dbPathLength < m_cBestAnt.m_dbPathLength)  
  378.             {  
  379.                 m_cBestAnt=m_cAntAry[j];  
  380.             }  
  381.         }  
  382.   
  383.         //更新环境信息素  
  384.         UpdateTrial();  
  385.   
  386.         //输出目前为止找到的最优路径的长度  
  387.         sprintf(cBuf,“\n[%d] %.0f”,i+1,m_cBestAnt.m_dbPathLength);  
  388.         printf(cBuf);  
  389.     }  
  390.   
  391. }  

下面是在控制台下的测试代码:

[cpp] 
view plain
copy
《蚁群算法求解TSP问题的源代码》
《蚁群算法求解TSP问题的源代码》

  1. int main()  
  2. {  
  3.     //用当前时间点初始化随机种子,防止每次运行的结果都相同  
  4.     time_t tm;  
  5.     time(&tm);  
  6.     unsigned int nSeed=(unsigned int)tm;  
  7.     srand(nSeed);  
  8.   
  9.     //开始搜索  
  10.     CTsp tsp;  
  11.   
  12.     tsp.InitData(); //初始化  
  13.     tsp.Search(); //开始搜索  
  14.   
  15.     //输出结果  
  16.     printf(“\nThe best tour is :\n”);  
  17.   
  18.     char cBuf[128];  
  19.     for (int i=0;i<N_CITY_COUNT;i++)  
  20.     {  
  21.         sprintf(cBuf,“%d “,tsp.m_cBestAnt.m_nPath[i]+1);  
  22.         if (i % 20 == 0)  
  23.         {  
  24.             printf(“\n”);  
  25.         }  
  26.         printf(cBuf);  
  27.     }  
  28.   
  29.     printf(“\n\nPress any key to exit!”);  
  30.     getchar();  
  31.   
  32.     return 0;  
  33. }  

在win32下可编写程序,步骤如下:1.新建一个win32工程,将蚁群算法和TSP的代码导入工程,并添加消息响应,当用户在界面上单击鼠标左键时开始运行算法,同时修改TSP类的search函数,在每完成一代后发送一条用户自定义消息到界面窗口:

SendMessage(m_hWnd,USERMSG_UPDATE,0,0);  //注意:此处不能为PostMessage函数,因为需要每一代更新界面,要等消息处理完成才能返回

自定义用户消息如下:

#define USERMSG_UPDATE WM_USER+2

2. 在窗口消息处理函数WndProc中添加代码如下:

1)对WM_PAINT进行相应的代码如下:

[cpp] 
view plain
copy
《蚁群算法求解TSP问题的源代码》
《蚁群算法求解TSP问题的源代码》

  1. hdc = BeginPaint(hWnd,&ps);  
  2. // TODO: 在此添加任意绘图代码…  
  3. for(int i=0;i<51;i++)  
  4. {  
  5.     RECT rect;  
  6.     rect.left = x_Ary[i]-2;  
  7.     rect.right = x_Ary[i]+2;  
  8.     rect.top = y_Ary[i]-2;  
  9.     rect.bottom = y_Ary[i]+2;  
  10.     Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom);  
  11.     HGDIOBJ brush = GetStockObject(DC_BRUSH);  
  12.     COLORREF col(RGB(124,252,0));  
  13.     SetDCBrushColor(hdc,col);  
  14.     FillRect(hdc,&rect,(HBRUSH)brush);  
  15.     char ch[3];  
  16.     memset(ch,0,3);  
  17.     sprintf(ch,“%d”,i+1);  
  18.     TextOutA(hdc,x_Ary[i]+2,y_Ary[i]+2,LPCSTR(ch),strlen(ch));  
  19. }  
  20. EndPaint(hWnd, &ps);  

2)鼠标左键消息WM_LBUTTONDOWN响应:

[cpp] 
view plain
copy
《蚁群算法求解TSP问题的源代码》
《蚁群算法求解TSP问题的源代码》

  1. RECT rect;  
  2.     GetClientRect(hWnd,&rect);  
  3.     InvalidateRect(hWnd,&rect,true);  
  4.     UpdateWindow(hWnd);  
  5.     time_t tm;  
  6.     time(&tm);  
  7.     unsigned int nSeed=(unsigned int)tm;  
  8.     srand(nSeed);  
  9.     //开始搜索  
  10.     CTsp tsp(hWnd);  
  11.     tsp.InitData(); //初始化  
  12.     tsp.Search(); //开始搜索  

3)对用户自定义消息USERMSG_UPDATE的响应:

[cpp] 
view plain
copy
《蚁群算法求解TSP问题的源代码》
《蚁群算法求解TSP问题的源代码》

  1. RECT rect;  
  2. GetClientRect(hWnd,&rect);  
  3. InvalidateRect(hWnd,&rect,true);  
  4. UpdateWindow(hWnd);  
  5. hdc = GetDC(hWnd);  
  6. HGDIOBJ pen = GetStockObject(DC_PEN);  
  7. COLORREF col(RGB(124,252,0));  
  8. SetDCPenColor(hdc,col);  
  9. for(int i=0;i<50;i++)  
  10. {  
  11.     int n = bestPath[i];  
  12.     int m = bestPath[i+1];  
  13.     MoveToEx(hdc,x_Ary[n],y_Ary[n],NULL);  
  14.     LineTo(hdc,x_Ary[m],y_Ary[m]);  
  15. }  
  16. MoveToEx(hdc,x_Ary[bestPath[50]],y_Ary[bestPath[50]],NULL);  
  17. LineTo(hdc,x_Ary[bestPath[0]],y_Ary[bestPath[0]]);  
  18. ReleaseDC(hWnd, hdc);  

4)添加全局变量bestPath,用以保存找到的最佳路径,并在TSP类的search函数中每一代进行更新

[cpp] 
view plain
copy
《蚁群算法求解TSP问题的源代码》
《蚁群算法求解TSP问题的源代码》

  1. for(int k=0;k<N_CITY_COUNT;k++)  
  2. {  
  3.     bestPath[k] = m_cBestAnt.m_nPath[k];  
  4. }  

最后程序的运行结果如下:

《蚁群算法求解TSP问题的源代码》

    原文作者:蚁群算法
    原文地址: https://blog.csdn.net/xuxx09/article/details/42713383
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞