天气与日历 切换到窄版

 找回密码
 立即注册
中国膜结构网
十大进口膜材评选 十大国产膜材评选 十大膜结构设计评选 十大膜结构公司评选
查看: 53|回复: 0

C++蚁群算法,带图,超详细

[复制链接]
  • TA的每日心情
    开心
    昨天 15:13
  • 签到天数: 153 天

    [LV.7]常住居民III

    3456

    主题

    553

    回帖

    214748万

    积分

    管理员

    中国膜结构网www.mjgou.com

    积分
    2147483647
    QQ
    发表于 2024-7-16 23:12:53 | 显示全部楼层 |阅读模式
    1. //main.cpp
    2. #include"Head.h"

    3. int main() {
    4.         //更新随机种子
    5.         srand((unsigned)time(NULL));

    6.         Graph* graph = new Graph;

    7.         graph->readCity();//启用文件读取,注销掉则为随机构造城市

    8.         graph->innitial_Graph();
    9.         AntColony* ant_colony = new AntColony;
    10.         ant_colony->innitial_AntColony();

    11.         for (int NC_now = 0; NC_now < NC_MAX; ++NC_now) {
    12.                 for (int i = 1; i < N; ++i) {
    13.                         ant_colony->ChooseNextCity(graph, i);
    14.                 }
    15.                 ant_colony->Update(graph,NC_now);
    16.                 ant_colony->innitial_AntColony();
    17.         }
    18.        
    19.         cout << "The BestLength=" << BestLength << endl;

    20.         ShowByPython(graph);

    21.         int last, next;
    22.         double sum = 0;
    23.         for (int i = 1; i < N; ++i) {
    24.                 last = BestPath[i-1];
    25.                 next = BestPath[i];
    26.                 cout << "Travel " << i << " : " << last << "   \t-> " << next << " \tdistante: " << graph->Length[last][next] << endl;
    27.                 sum += graph->Length[last][next];
    28.         }
    29.         last = BestPath[N - 1];
    30.         next = BestPath[0];
    31.         cout << "Travel " << N << " : " << last << "   \t-> " << next << " \tdistante: " << graph->Length[last][next] << endl;
    32.         sum += graph->Length[last][next];
    33.         cout << "最优解路程和 = " << sum << endl;
    34.         cout << "TSPlib上的已知最优解 :" << graph->KnowBest << endl;
    35.         cout << "与已知最优解的偏差为 :" << ((sum - graph->KnowBest) / graph->KnowBest) * 100 << "%" << endl;//最后两句必须启用文件读取才有效

    36.         delete graph;
    37.         delete ant_colony;
    38.         return 0;
    39. }
    复制代码



    1. //Head.h
    2. #include<iostream>
    3. #include<cstdlib>
    4. #include<string>
    5. #include<cmath>
    6. #include<fstream>
    7. #include<Python.h>
    8. using namespace std;
    9. #define PATH "E:\\TSPlib\\ch150.txt"//TSPlib数据文件的路径

    10. #define N 150                //城市数量
    11. #define M 100                //蚂蚁数量
    12. #define NC_MAX 1200        //迭代次数
    13. #define α 1                //信息素浓度重要性
    14. #define β 1                //启发式重要性
    15. #define Q 100                //蚂蚁所携带信息素
    16. #define ρ 0.2                //蒸发系数

    17. //注意:如果从文件中读取City,目前需要手动调整城市数量N,要与文件中保持一致
    18. //并且修改 PATH 路径与启用main函数中的readCity函数

    19. //以下数据结构用于最后分析
    20. int BestPath_PerRound[NC_MAX][N] = { 0 };//记录每轮的最优路径
    21. double BestLength_PerRound[NC_MAX] = { 0 };//记录每轮最优路径的长度
    22. int BestPath[N] = { 0 };//全局最短路径(后一轮迭代未必一定比前一轮更优,只是总体是这样,不绝对),不保存每轮的信息
    23. double BestLength = 1000000;//全局最短路径长度
    24. double AverageLength_PerRound[NC_MAX] = { 0 };//记录每轮所有蚂蚁所走路径的平均长度

    25. class City {
    26. public:
    27.         //无参构造函数,创建城市时默认在[0,999]内随机获得x,y坐标
    28.         City() {
    29.                 x = rand() % 1000;
    30.                 y = rand() % 1000;
    31.         }
    32.         double x;
    33.         double y;
    34. };
    35. class Graph {
    36. public:
    37.         City citys[N];//无参构造函数创建N个城市
    38.         double Length[N][N] = { 0 };//路径长度表
    39.         double tao[N][N] = { 0 };//信息素浓度表
    40.         double Heuristic[N][N] = { 0 };//启发式表,将城市之间距离的倒数作为启发函数
    41. public:
    42.         //使用fstream读取文件中的城市坐标,并创建城市
    43.         int KnowBest;//读取文件时存放已知最优解
    44.         void readCity() {
    45.                 ifstream CityFile;
    46.                 CityFile.open(PATH, ios::in);
    47.                 if (!CityFile.is_open()) {
    48.                         cout << "Open file failure" << endl;
    49.                         exit(0);
    50.                 }
    51.                 CityFile >> KnowBest;
    52.                 cout << "The known best result is :" << KnowBest << endl;
    53.                 int a;double b[2];
    54.                 while (!CityFile.eof()) {
    55.                         CityFile >> a >> b[0] >> b[1];
    56.                         citys[a - 1].x = b[0];
    57.                         citys[a - 1].y = b[1];
    58.                 }
    59.                 CityFile.close();
    60.         }
    61.         //初始化城市图,并计算各城市之间的距离
    62.         void innitial_Graph() {
    63.                 double x = 0, y = 0;
    64.                 for (int i = 0; i < N; ++i) {
    65.                         for (int j = 0; j < N; ++j) {
    66.                                 x = citys[i].x - citys[j].x;
    67.                                 y = citys[i].y - citys[j].y;
    68.                                 Length[i][j] = sqrt(pow(x, 2) + pow(y, 2));//就是两点间距离公式
    69.                                 if (i == j) {
    70.                                         Length[i][j] = 10000;//默认城市到自己的距离为10000,防止启发式表出现无穷大,并不会计算城市自己到自己的概率
    71.                                 }
    72.                                 else {
    73.                                         if (x == 0 && y == 0) {
    74.                                                 //这种情况是城市坐标完全重合,如果遇到这种情况则不能继续计算了,否则i与j之间的距离为0,启发式就会为无穷大
    75.                                                 //随之p的分子和分母都会变成无穷大,无穷大除无穷大...
    76.                                                 cout << "innitial_Graph ERROR!!! City overlapping, please retry." << endl;
    77.                                                 cout << "City :" << i << " and City :" << j << endl;
    78.                                                 exit(0);
    79.                                         }
    80.                                 }
    81.                                 Heuristic[i][j] = 1 / Length[i][j];//将距离的倒数作为启发式
    82.                                 tao[i][j] = 1;//信息素tao不能初始化为0
    83.                         }
    84.                 }
    85.         }
    86. };
    87. class AntColony {
    88. public:
    89.         int tabu[M][N] = { 0 };//禁忌列表,同时记录了蚂蚁的路径,每个元素取值为[0,N-1]
    90.         int allow[M][N] = { 0 };//允许列表,完全依赖于禁忌列表,只是为了算法方便一些而设置,无法记录路径,每个元素取值为[0,1]
    91.         double probability[M][N] = { 0 };//概率表,存放各蚂蚁选择下一作城市的概率
    92.         double cumulative_probability[M][N] = { 0 };//累积概率表,用于轮盘赌算法随机选择城市
    93. public:

    94.         //每轮迭代前都应该被调用一次
    95.         void innitial_AntColony() {
    96.                 //初始化各列表
    97.                 for (int i = 0; i < M; ++i) {
    98.                         for (int j = 0; j < N; ++j) {
    99.                                 tabu[i][j] = -1;
    100.                                 allow[i][j] = 1;
    101.                                 probability[i][j] = 0;
    102.                                 cumulative_probability[i][j] = 0;
    103.                         }
    104.                 }
    105.                 //为每一只蚂蚁随机一个初始城市,并将其加入禁忌列表
    106.                 for (int i = 0; i < M; i++) {
    107.                         tabu[i][0] = rand() % N;
    108.                         allow[i][tabu[i][0]] = 0;
    109.                 }
    110.         }

    111.         //求取概率表和累积概率表,然后根据轮盘赌算法选择下一个城市,每轮迭代应该被调用N-1次(初始化时已经有一个城市了)
    112.         void ChooseNextCity(Graph* graph, int times) {//times表示此轮迭代已经是第几次调用这个函数了,times应该从1开始,到N-1次结束

    113.                 //求概率表
    114.                 double sum = 0;
    115.                 int city_now = -1;
    116.                 for (int i = 0; i < M; ++i) {
    117.                         sum = 0;
    118.                         city_now = tabu[i][times - 1];//蚂蚁i目前在城市city_now
    119.                         for (int j = 0; j < N; ++j) {
    120.                                 if (allow[i][j] == 1) {
    121.                                         probability[i][j] = pow(graph->tao[city_now][j], α) * pow(graph->Heuristic[city_now][j], β);
    122.                                         sum += probability[i][j];
    123.                                 }
    124.                                 else {
    125.                                         probability[i][j] = 0;
    126.                                         sum += 0;
    127.                                 }
    128.                         }
    129.                         //上面求出的probability表并不是真正的概率表,而只是概率的分子,下面求出真正的概率表
    130.                         for (int j = 0; j < N; ++j) {
    131.                                 probability[i][j] = probability[i][j] / sum;
    132.                         }
    133.                 }

    134.                 //用概率表求累积概率表
    135.                 for (int i = 0; i < M; ++i) {
    136.                         cumulative_probability[i][0] = probability[i][0];
    137.                         for (int j = 1; j < N; ++j) {
    138.                                 cumulative_probability[i][j] = cumulative_probability[i][j - 1] + probability[i][j];
    139.                         }
    140.                 }

    141.                 //依据累积概率表,用轮盘赌算法为每只蚂蚁选择下一个城市
    142.                 double p = 0;
    143.                 for (int i = 0; i < M; ++i) {
    144.                         p = rand() % 1000;
    145.                         p /= 1000;
    146.                         for (int j = 0; j < N; ++j) {
    147.                                 if (p <= cumulative_probability[i][j]) {
    148.                                         //如果满足此式,则让蚂蚁i前往城市j(下面更新tabu表的操作就是从逻辑上把蚂蚁移动到城市j)
    149.                                         tabu[i][times] = j;
    150.                                         allow[i][j] = 0;
    151.                                         break;
    152.                                 }
    153.                         }
    154.                 }
    155.         }

    156.         //更新函数每次迭代后都应该被调用一次,用于更新信息素表graph->tabu,并记录本轮迭代的相关信息(最优路径,最优路径的长度,所有蚂蚁所走路径的平均长度)
    157.         //NC_now表示目前的迭代次数,应该从0开始,到NC_MAX-1结束,依次调用此函数
    158.         void Update(Graph* graph, int NC_now) {
    159.                 double delta_ktao = 0;        //用于保存当前蚂蚁留在所经边的信息素
    160.                 double delta_tao[N][N] = { 0 };        //此轮迭代的信息素增量表,表示本轮信息素的增量,配合蒸发系数更新信息素表
    161.                 double sum_Length[M] = { 0 };        //保存此轮每只蚂蚁所经过的路径长度

    162.                 int last_city, next_city;
    163.                 //遍历tabu表,计算每只蚂蚁的路径长度,存放在sum_Length[]中
    164.                 for (int i = 0; i < M; ++i) {
    165.                         for (int j = 1; j < N; ++j) {
    166.                                 last_city = tabu[i][j - 1];
    167.                                 next_city = tabu[i][j];
    168.                                 sum_Length[i] += graph->Length[last_city][next_city];
    169.                         }
    170.                         //还要再加上终点到起点的距离
    171.                         last_city = tabu[i][N - 1];
    172.                         next_city = tabu[i][0];
    173.                         sum_Length[i] += graph->Length[last_city][next_city];
    174.                 }
    175.                 //遍历tabu表,计算信息素增量表delta_tao[][]
    176.                 for (int i = 0; i < M; ++i) {
    177.                         delta_ktao = Q / sum_Length[i];
    178.                         for (int j = 1; j < N; ++j) {
    179.                                 last_city = tabu[i][j - 1];
    180.                                 next_city = tabu[i][j];
    181.                                 delta_tao[last_city][next_city] += delta_ktao;
    182.                         }
    183.                 }
    184.                 //利用信息素增量表和蒸发系数更新信息素表tao[][]
    185.                 for (int i = 0; i < N; ++i) {
    186.                         for (int j = 0; j < N; ++j) {
    187.                                 graph->tao[i][j] = graph->tao[i][j] * (1 - ρ) + delta_tao[i][j];
    188.                         }
    189.                 }

    190.                 //计算本轮最优路径,最优路径的长度,所有蚂蚁所走路径的平均长度
    191.                 int flag = 0;
    192.                 double min = 1000000, sum = 0;        //min的初始值必须是一个足够大的值
    193.                 for (int i = 0; i < M; ++i) {
    194.                         sum += sum_Length[i];
    195.                         if (min > sum_Length[i]) {
    196.                                 min = sum_Length[i];
    197.                                 flag = i;//标记最好的蚂蚁
    198.                         }
    199.                 }
    200.                 //记录本轮信息至全局变量中
    201.                 for (int i = 0; i < N; ++i) {
    202.                         BestPath_PerRound[NC_now][i] = tabu[flag][i];
    203.                 }
    204.                 BestLength_PerRound[NC_now] = min;
    205.                 AverageLength_PerRound[NC_now] = sum / M;


    206.                 //更新全局最优路径和其长度
    207.                 if (BestLength > min) {
    208.                         for (int i = 0; i < N; ++i) {
    209.                                 BestPath[i] = BestPath_PerRound[NC_now][i];
    210.                         }
    211.                         BestLength = min;
    212.                 }

    213.                 //用2-opt局部搜索优化本轮最优路径并用信息素强化
    214.                 {
    215.                         int TempPath[N];
    216.                         int flag = false;
    217.                         int t;
    218.                         for (int i = 0; i < N; ++i) {
    219.                                 TempPath[i] = BestPath_PerRound[NC_now][i];
    220.                         }
    221.                         for (int a = 0; a < N-1; ++a) {
    222.                                 //如果路径被优化为新路径,则再对新路径从头来一次局部搜索
    223.                                 if (flag == true) {
    224.                                         a = 0;
    225.                                         flag = false;
    226.                                 }
    227.                                 for (int b = a + 1; b < N; ++b) {
    228.                                         //逆序a~b的路径
    229.                                         for (int i = a, j = b; i < j; ++i, --j) {
    230.                                                 t = TempPath[i];
    231.                                                 TempPath[i] = TempPath[j];
    232.                                                 TempPath[j] = t;
    233.                                         }
    234.                                         //重新求优化后的路径长度,加上终点到起点的距离
    235.                                         sum = 0;
    236.                                         for (int i = 1; i < N; ++i) {
    237.                                                 last_city = TempPath[i - 1];
    238.                                                 next_city = TempPath[i];
    239.                                                 sum += graph->Length[last_city][next_city];
    240.                                         }
    241.                                         last_city = TempPath[N - 1];
    242.                                         next_city = TempPath[0];
    243.                                         sum += graph->Length[last_city][next_city];
    244.                                         //如果此解更优则更新本轮最优解
    245.                                         if (sum < BestLength_PerRound[NC_now]) {
    246.                                                 flag = true;//如果路径被更新,则局部搜索从0开始
    247.                                                 //先更新平均路径再更新最优路径
    248.                                                 AverageLength_PerRound[NC_now] = (AverageLength_PerRound[NC_now] * M - BestLength_PerRound[NC_now] + sum) / M;
    249.                                                 BestLength_PerRound[NC_now] = sum;
    250.                                                 for (int i = 0; i < N; ++i) {
    251.                                                         BestPath_PerRound[NC_now][i] = TempPath[i];
    252.                                                 }
    253.                                                 //如果比全局最优解还优,则更新全局最优解
    254.                                                 if (sum < BestLength) {
    255.                                                         for (int i = 0; i < N; ++i) {
    256.                                                                 BestPath[i] = TempPath[i];
    257.                                                         }
    258.                                                         BestLength = sum;
    259.                                                 }
    260.                                         }
    261.                                 }
    262.                         }
    263.                         //使用2opt局部搜索获得更强的解之后,给最优路径追加信息素奖励
    264.                         double reward = Q / sum;
    265.                         for (int i = 1; i < N; ++i) {
    266.                                 last_city = BestPath[i-1];
    267.                                 next_city = BestPath[i];
    268.                                 graph->tao[last_city][next_city] += reward;
    269.                         }
    270.                 }
    271.         }
    272. };

    273. //此函数的目的是为了用图展示出蚁群算法的结果,用C++调用python的matplotlib库
    274. bool ShowByPython(Graph* graph) {

    275.         //C++中初始化python环境
    276.         Py_Initialize();
    277.         if (!Py_IsInitialized()) {
    278.                 std::cout << "Py_Initialize Error!" << std::endl;
    279.                 return false;
    280.         }

    281.         try {
    282.                 //执行python语句
    283.                 PyRun_SimpleString("import sys");
    284.                 PyRun_SimpleString("import matplotlib.pyplot as plt");
    285.                 string importPy = "sys.argv = ['suibiantian']";
    286.                 PyRun_SimpleString(importPy.c_str());

    287.                 double x, y;
    288.                 PyRun_SimpleString("plt.figure(num=1)");
    289.                 PyRun_SimpleString("plt.title('Ant Colony algorithm for solving TSP')");//蚁群算法解决TSP问题
    290.                 PyRun_SimpleString("plt.xlabel('x')");
    291.                 PyRun_SimpleString("plt.ylabel('y')");
    292.                 importPy= "plt.xlabel('Shortest=" + to_string(BestLength) + "')";
    293.                 PyRun_SimpleString(importPy.c_str());
    294.                 for (int i = 0; i < N; ++i) {
    295.                         x = graph->citys[i].x;//Graph[i].get_x();
    296.                         y = graph->citys[i].y;
    297.                         importPy = "plt.scatter(" + to_string(x) + "," + to_string(y) + ")";
    298.                         PyRun_SimpleString(importPy.c_str());
    299.                 }

    300.                 int last_city, next_city;
    301.                 double X1, X2, Y1, Y2;
    302.                 string str;
    303.                 //把全局最优路径按顺序画出来,画在第一副图上
    304.                 PyRun_SimpleString("plt.figure(num=1)");
    305.                 for (int i = 1; i < N; ++i) {
    306.                         last_city = BestPath[i - 1];
    307.                         next_city = BestPath[i];
    308.                         X1 = graph->citys[last_city].x;
    309.                         Y1 = graph->citys[last_city].y;
    310.                         X2 = graph->citys[next_city].x;
    311.                         Y2 = graph->citys[next_city].y;
    312.                         str = "plt.plot([" + to_string(X1) + "," + to_string(X2) + "],[" + to_string(Y1) + "," + to_string(Y2) + "])";
    313.                         PyRun_SimpleString(str.c_str());
    314.                 }
    315.                 //把终点到起点的线也画上
    316.                 last_city = BestPath[N - 1];
    317.                 next_city = BestPath[0];
    318.                 X1 = graph->citys[last_city].x;
    319.                 Y1 = graph->citys[last_city].y;
    320.                 X2 = graph->citys[next_city].x;
    321.                 Y2 = graph->citys[next_city].y;
    322.                 str = "plt.plot([" + to_string(X1) + "," + to_string(X2) + "],[" + to_string(Y1) + "," + to_string(Y2) + "])";
    323.                 PyRun_SimpleString(str.c_str());

    324.                 //下面展示随着迭代进行,每轮最优路径长度的变化,这是第二幅图
    325.                 double last = 0, next = 0;
    326.                 //string str;
    327.                 PyRun_SimpleString("plt.figure(num=2)");
    328.                 PyRun_SimpleString("plt.title('ShortestLength Convergence graph')");//最优路径收敛图
    329.                 PyRun_SimpleString("plt.xlabel('times of iterations')");
    330.                 PyRun_SimpleString("plt.ylabel('BestLength')");
    331.                 for (int i = 1; i < NC_MAX; ++i) {
    332.                         last = BestLength_PerRound[i - 1];
    333.                         next = BestLength_PerRound[i];
    334.                         str = "plt.plot([" + to_string(i - 1) + "," + to_string(i) + "],[" + to_string(last) + "," + to_string(next) + "])";
    335.                         PyRun_SimpleString(str.c_str());
    336.                 }

    337.                 //下面展示随着迭代进行,每轮平均路径长度的变化,这是第三幅图
    338.                 PyRun_SimpleString("plt.figure(num=3)");
    339.                 PyRun_SimpleString("plt.title('AverageLength Convergence graph')");//平均路径收敛图
    340.                 PyRun_SimpleString("plt.xlabel('times of iterations')");
    341.                 PyRun_SimpleString("plt.ylabel('AverageLength')");
    342.                 for (int i = 1; i < NC_MAX; ++i) {
    343.                         last = AverageLength_PerRound[i - 1];
    344.                         next = AverageLength_PerRound[i];
    345.                         str = "plt.plot([" + to_string(i - 1) + "," + to_string(i) + "],[" + to_string(last) + "," + to_string(next) + "])";
    346.                         PyRun_SimpleString(str.c_str());
    347.                 }

    348.                 //展示上面描绘的三幅图
    349.                 PyRun_SimpleString("plt.show()");
    350.         }
    351.         catch (...) {
    352.                 PyErr_Print();
    353.                 PyErr_Clear();
    354.                 Py_Finalize();
    355.                 return false;
    356.         }
    357.         Py_Finalize();
    358.         return true;
    359. }
    复制代码

     

     

     

     

    C++蚁群算法,带图,超详细
    中国膜结构网打造全中国最好的膜结构综合平台 ,统一协调膜结构设计,膜结构施工,膜材采购,膜材定制,膜结构预算全方位服务。 中国空间膜结构协会合作单位。
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|中国膜结构网|中国膜结构协会|进口膜材|国产膜材|ETFE|PVDF|PTFE|设计|施工|安装|车棚|看台|污水池| |网站地图

    GMT+8, 2024-9-8 09:23 , Processed in 0.065030 second(s), 23 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表