天气与日历 切换到窄版

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

C++蚁群算法

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

    [LV.7]常住居民III

    3456

    主题

    553

    回帖

    214748万

    积分

    管理员

    中国膜结构网www.mjgou.com

    积分
    2147483647
    QQ
    发表于 2024-7-16 23:11:41 | 显示全部楼层 |阅读模式
    1. #include<iostream>
    2. #include<string>
    3. #include<math.h>
    4. #include<fstream>
    5. #include<vector>
    6. #include<map>
    7. #include<unordered_map>
    8. #include<algorithm>
    9. #include<conio.h>

    10. using namespace std;

    11. #pragma region 变量与常量的定义

    12. //数据文件存放的路径
    13. constexpr auto FILE_PATH = "D:\\data.txt";
    14. //城市数量
    15. const int CITY_NUMBER = 19;
    16. //蚂蚁数量(一般为城市数量的1.5倍)
    17. const int ANT_NUMBER = 50;
    18. //最大迭代次数
    19. const int  MAX_ITERATIONS_NUMBER = 150;
    20. //路径数量
    21. const int  PATH_NUMBER = 74;
    22. //启发因子,信息素浓度重要性
    23. const double ALPHA = 1.0;
    24. //启发式重要性
    25. const double BETA = 2.0;
    26. //蚂蚁所携带总的信息素
    27. const double Q = 100.0;
    28. //信息素蒸发系数
    29. const double ROU = 0.5;

    30. //两两城市之间的信息素矩阵
    31. vector<vector<double>> pheromoneMatrix;
    32. //两两城市之间的距离
    33. vector<vector<double>> cityDistance;
    34. //下一代的信息素矩阵
    35. vector<vector<double>> nextPheromoneMatrix;
    36. //启发信息矩阵=1/cityDistance[i][j]
    37. vector<vector<double>> inspMartix;

    38. //关键字:string类型,值:int类型。分别对应保存每次迭代的最优路径和对应的路径距离。
    39. map<string, int>routResult;
    40. //含有充电设施的站点编号
    41. vector<int>rechargeNumber = { 3,4,7,8,12,14,16 };

    42. #pragma endregion

    43. #pragma region 蚂蚁
    44. class Ant {
    45. public:
    46.         //蚂蚁的当前位置
    47.         int antLoc;
    48.         //蚂蚁的禁忌表,存放已访问过的点
    49.         int taBu[CITY_NUMBER];
    50.         //蚂蚁走过路径的点的集合
    51.         int antPath[PATH_NUMBER];
    52.         //判断蚂蚁是否已经到达终点。True:表示到达,FALSE:表示未到达。
    53.         bool flag;
    54. };
    55. //初始化蚁群,大小为ANT_NUMBER
    56. Ant antColony[ANT_NUMBER];
    57. #pragma endregion

    58. #pragma region 城市
    59. class City {
    60. public:
    61.         //城市编号
    62.         int cityNum;
    63.         //选择每个点的概率
    64.         double cityProb;
    65. };
    66. //初始化城市
    67. City cityArray[CITY_NUMBER];
    68. //线性化选择概率,用于轮盘赌算法
    69. double lineCityProb[CITY_NUMBER];
    70. #pragma endregion

    71. #pragma region 矩阵初始化功能函数
    72. //res:表示待初始化的矩阵
    73. //temp:表示矩阵初始化的值
    74. void initMatrix(vector<vector<double>> &res, int temp) {
    75.         //定义中间变量v
    76.         vector<double>v;
    77.         for (int i = 0; i < CITY_NUMBER; ++i) {
    78.                 //清空v
    79.                 vector<double>().swap(v);
    80.                 for (int j = 0; j < CITY_NUMBER; ++j) {
    81.                         v.push_back(temp);
    82.                 }
    83.                 res.push_back(v);
    84.         }
    85. }
    86. #pragma endregion

    87. #pragma region 返回指定范围内的随机数
    88. ///                返回指定范围内的随机浮点数
    89. ///     @param dbLow                范围起始数   
    90. ///     @param dbUpper  范围终止数
    91. ///     @return                                        返回的此范围内的随机数
    92. double randomNumber(double dbLow, double dbUpper)
    93. {
    94.         double dbTemp = rand() / ((double)RAND_MAX + 1.0);
    95.         return dbLow + dbTemp * (dbUpper - dbLow);
    96. }
    97. #pragma endregion

    98. #pragma region 蚁群初始化
    99. void initAntsColony() {
    100.         //初始化禁忌表和行走路线
    101.         for (int i = 0; i < ANT_NUMBER; ++i) {
    102.                 for (int j = 0; j < CITY_NUMBER; ++j) {
    103.                         //初始化蚁群的禁忌表,设置每只蚂蚁的禁忌表初始化为-1,代表从未访问任何点
    104.                         antColony[i].taBu[j] = -1;
    105.                 }
    106.                 for (int j = 0; j < PATH_NUMBER; ++j) {
    107.                         //初始化蚁群的行走路径,设置每只蚂蚁的路径初始化为-1,代表还未经过任何点
    108.                         antColony[i].antPath[j] = -1;
    109.                 }
    110.         }

    111.         //将蚂蚁放入初始位置,此处设置每只蚂蚁的出发点为0,代表从源点出发
    112.         for (int i = 0; i < ANT_NUMBER; ++i) {
    113.                 //设置蚂蚁的当前位置为出发位置0
    114.                 antColony[i].antLoc = 0;
    115.                 //将当前位置更新到每只蚂蚁的禁忌表中,代表已经访问过此点
    116.                 antColony[i].taBu[0] = 0;
    117.                 //将当前位置更新到每只蚂蚁的行走路径中,代表路径中已有此点
    118.                 antColony[i].antPath[0] = 0;
    119.                 //将每只蚂蚁的flag设置为0,代表每只蚂蚁都还未到达终点
    120.                 antColony[i].flag = 0;
    121.         }
    122. }
    123. #pragma endregion

    124. #pragma region 初始化城市
    125. void initCity() {
    126.         for (int i = 0; i < CITY_NUMBER; ++i) {
    127.                 //初始化城市结构体
    128.                 //初始化每个城市的编号为-1
    129.                 cityArray[i].cityNum = -1;
    130.                 //初始化每个城市的选择概率为0
    131.                 cityArray[i].cityProb = 0;
    132.                 //初始化线性选择概率为0
    133.                 lineCityProb[i] = 0;
    134.         }
    135. }
    136. #pragma endregion

    137. #pragma region 初始化所需的各种矩阵,并读取文件距离数据
    138. void initVariousMatrix() {
    139.         //初始化城市距离矩阵为-1
    140.         initMatrix(cityDistance, -1);

    141.         /*             数据文件的读取                */


    142.         //创建文件流对象
    143.         ifstream CityFile;
    144.         //打开文件
    145.         CityFile.open(FILE_PATH, ios::in);
    146.         //如果文件打开失败,则退出
    147.         if (!CityFile.is_open()) {
    148.                 cout << "Open file failure" << endl;
    149.                 exit(0);
    150.         }
    151.         //从文件中读取数据到城市距离矩阵之中
    152.         for (int i = 0; i < CITY_NUMBER; ++i) {
    153.                 for (int j = 0; j < CITY_NUMBER; ++j) {
    154.                         CityFile >> cityDistance[i][j];
    155.                 }
    156.         }
    157.         //关闭文件
    158.         CityFile.close();

    159.         //初始化信息素矩阵为0
    160.          initMatrix(pheromoneMatrix, 0);
    161.         //初始化下一代信息素矩阵为0
    162.         initMatrix(nextPheromoneMatrix, 0);
    163.         //初始化启发信息矩阵为0
    164.          initMatrix(inspMartix, 0);

    165.         for (int i = 0; i < CITY_NUMBER; ++i) {
    166.                 for (int j = 0; j < CITY_NUMBER; ++j) {
    167.                         if (cityDistance[i][j] != -1) {                 //如果两个城市之间有距离
    168.                                 inspMartix[i][j] = 1 / cityDistance[i][j];//启发信息为两两城市距离的倒数
    169.                                 pheromoneMatrix[i][j] = 1;                //路径上信息素浓度初始值为1
    170.                         }
    171.                 }
    172.         }
    173. }
    174. #pragma endregion

    175. #pragma region 判断城市j是否在蚂蚁k的禁忌表中
    176. bool ifCityInTabu(int k, int j) {
    177.         for (int i = 0; i < CITY_NUMBER; ++i) {
    178.                 //如果城市j,已经在蚂蚁k的禁忌表中,则返回1
    179.                 if (j == antColony[k].taBu[i]) {
    180.                         return 1;
    181.                 }
    182.         }
    183.         //如果不在蚂蚁k的禁忌表中,则返回0
    184.         return 0;
    185. }
    186. #pragma endregion

    187. #pragma region 蚂蚁k从当前城市i选择下一步行进的城市j的概率
    188. double nextCitySelProb(int k, int j) {
    189.         //初始化选择概率公式的分子
    190.         double p = 0;
    191.         //初始化选择概率公式的分母
    192.         double sum = 0;
    193.         //i保存蚂蚁k的当前位置
    194.         int i = antColony[k].antLoc;
    195.         //计算P
    196.         p = pow(pheromoneMatrix[i][j], ALPHA) * pow(inspMartix[i][j], BETA);
    197.         //计算sum
    198.         for (int m = 0; m < CITY_NUMBER; ++m) {
    199.                 if (cityDistance[i][j] != -1 && !ifCityInTabu(k, m)) {
    200.                         sum += pow(pheromoneMatrix[i][m], ALPHA)*pow(inspMartix[i][m], BETA);
    201.                 }
    202.         }
    203.         //返回从i--j的选择概率
    204.         return (p / sum);
    205. }
    206. #pragma endregion

    207. #pragma region 更新蚂蚁k的禁忌表信息
    208. void updateAntTabu(int k, int j) {
    209.         //蚂蚁k的当前位置赋值为j
    210.         antColony[k].antLoc = j;
    211.         for (int i = 0; i < CITY_NUMBER; ++i) {
    212.                 //如果蚂蚁k还未访问过j,则将蚂蚁k的禁忌表信息添加j
    213.                 if (antColony[k].taBu[i] == -1) {
    214.                         antColony[k].taBu[i] = j;
    215.                         break;
    216.                 }
    217.         }
    218.         //同理,将蚂蚁k的行走路径中更新一个j
    219.         for (int i = 0; i < PATH_NUMBER; ++i) {
    220.                 if (antColony[k].antPath[i] == -1) {
    221.                         antColony[k].antPath[i] = j;
    222.                         break;
    223.                 }
    224.         }
    225. }
    226. #pragma endregion

    227. #pragma region 轮盘赌选择下一步行进的城市
    228. //蚂蚁k,选择前进的地点j的概率
    229. int nextCitySelect(int k, int f) {

    230.         //记录蚂蚁可行进的城市个数,用于后面的计算
    231.         int c = 0;

    232.         //step 1:计算可行进的各城市的选择概率
    233.         for (int m = 0; m < CITY_NUMBER; ++m) {
    234.                 //若城市(i,j)之间有路且j不在蚂蚁k的禁忌表中,则计算概率
    235.                 if (cityDistance[antColony[k].antLoc][m] != -1 && !ifCityInTabu(k, m)) {
    236.                         //对应的城市编号存入数组中
    237.                         cityArray[c].cityNum = m;
    238.                         //选择概率存入数组中
    239.                         cityArray[c].cityProb = nextCitySelProb(k, m);
    240.                         ++c;
    241.                 }
    242.         }

    243.         //step 2:线性化选择概率
    244.         for (int m = 0; m < c; ++m) {
    245.                 for (int n = m; n >= 0; n--) {
    246.                         //用于轮盘赌算法,将选择概率线性化累加
    247.                         lineCityProb[m] += cityArray[n].cityProb;
    248.                 }
    249.         }

    250.         //step 3 产生随机数选择城市
    251.         //产生随机浮点数,范围0-1
    252.         double r = randomNumber(0, 1);
    253.         //选取的目标城市
    254.         int j = 0;
    255.         for (int m = 0; m < CITY_NUMBER; ++m) {
    256.                 if (r <= lineCityProb[m]) {
    257.                         //将当前选择前进的城市编号赋值给j
    258.                         j = cityArray[m].cityNum;
    259.                         //将地点j更新至蚂蚁k的禁忌表中,代表已经访问过此点
    260.                         updateAntTabu(k, j);
    261.                         if (j == f) {
    262.                                 //若蚂蚁k下一步城市为目的地城市,则修改标志为1
    263.                                 antColony[k].flag = 1;
    264.                         }
    265.                         //return j;
    266.                         return 0;
    267.                 }
    268.         }
    269.         //return f;
    270.         return 0;

    271. }
    272. #pragma endregion

    273. #pragma region 计算路径长度
    274. int getAntLen(Ant ant) {
    275.         //定义路径长度为0
    276.         int len = 0;
    277.         for (int i = 0; i < PATH_NUMBER - 1; ++i) {
    278.                 //如果蚂蚁行走的路径中有-1,表示未走过此点,则退出循环
    279.                 if (ant.antPath[i] == -1 || ant.antPath[i + 1] == -1)
    280.                         break;
    281.                 //若走过有路径,则不断累加距离结果
    282.                 else
    283.                         len += cityDistance[ant.antPath[i]][ant.antPath[i + 1]];
    284.         }
    285.         //返回路径长度
    286.         return len;
    287. }
    288. #pragma endregion

    289. #pragma region 计算最优路径对应的蚂蚁编号
    290. int getBestPathAntNumber() {
    291.         //初始化数组d为-1,保存所有蚂蚁的行走路径
    292.         vector<int>d(ANT_NUMBER, -1);
    293.         //假设定义蚂蚁k的路线到达目的地节点最短,即走过的路径为最短路径
    294.         int k = 0;
    295.         //将所有路径距离存入d中
    296.         for (int i = 0; i < ANT_NUMBER; i++)
    297.         {
    298.                 d.push_back(getAntLen(antColony[i]));
    299.         }
    300.         //定义指向最小路径的迭代器
    301.         auto min = min_element(d.begin(), d.end());
    302.         //计算此最短路径所对应的下标,此为蚂蚁的编号k
    303.         k = distance(d.begin(), min);
    304.         vector<int>(d).swap(d);
    305.         //返回蚂蚁k
    306.         return k;
    307. }
    308. #pragma endregion

    309. #pragma region 打印最优路径所对应的蚂蚁K的路径和距离
    310. void printBestPath(int k, int f) {
    311.         //初始化变量res,存放路线
    312.         string res = "";
    313.         cout << " 最短路径为:";

    314.         for (int i = 0; i < PATH_NUMBER - 1; ++i) {
    315.                 //如果蚂蚁k的第i条路径为-1,表示没有走过此点,退出循环
    316.                 if (antColony[k].antPath[i] == -1)
    317.                         break;
    318.                 //打印蚂蚁k的第i条路径
    319.                 cout << antColony[k].antPath[i];


    320.                 //将路径转化为字符串形式存入res中,方便打印输出
    321.                 res += to_string(antColony[k].antPath[i]);

    322.                 //若蚂蚁k的i+1条路径不为-1,代表访问过此点。即i--->i+1有路线。
    323.                 if (antColony[k].antPath[i + 1] != -1) {
    324.                         //打印"->"
    325.                         cout << "->";


    326.                         // 若此点含有充电设施
    327.                         if (find(rechargeNumber.begin(), rechargeNumber.end(), antColony[k].antPath[i + 1]) != rechargeNumber.end()) {
    328.                                 res += "->(可充电站点)";
    329.                         }
    330.                         else {
    331.                                 res += "->";
    332.                         }

    333.                 }

    334.         }
    335.         cout << endl;
    336.         cout << " 对应距离为:" << getAntLen(antColony[k]) << endl;

    337.         //把每次距离结果保存到map中:关键字:路线,值:对应的路径长度
    338.         routResult[res] = getAntLen(antColony[k]);
    339.         res.swap(res);
    340.         //return routResult;
    341. }
    342. #pragma endregion

    343. #pragma region 更新信息素矩阵
    344. void updatePherMartix() {
    345.         for (int i = 0; i < ANT_NUMBER; ++i) {
    346.                 //全局更新信息素矩阵
    347.                 if (antColony[i].flag == 1) {
    348.                         for (int j = 0; j < PATH_NUMBER - 1; ++j) {
    349.                                 if (antColony[i].antPath[j] == -1 || antColony[i].antPath[j + 1] == -1)
    350.                                         break;
    351.                                 else
    352.                                         nextPheromoneMatrix[antColony[i].antPath[j]][antColony[i].antPath[j + 1]]
    353.                                         += Q / getAntLen(antColony[i]);
    354.                         }
    355.                 }
    356.         }
    357.         //更新下一代信息素矩阵
    358.         for (int i = 0; i < CITY_NUMBER; ++i) {
    359.                 for (int j = 0; j < CITY_NUMBER; ++j) {
    360.                         nextPheromoneMatrix[i][j] =
    361.                                 (1 - ROU) * pheromoneMatrix[i][j] + nextPheromoneMatrix[i][j];
    362.                 }
    363.         }

    364. }
    365. #pragma endregion

    366. #pragma region 迭代过程
    367. void evolution(int city) {


    368.         cout << "开始进行迭代........." << endl;

    369.         //初始化参数
    370.         initAntsColony();
    371.         initCity();
    372.         initVariousMatrix();


    373.         int gen = 0;
    374.         while (gen < MAX_ITERATIONS_NUMBER) {
    375.                 int p = 0;
    376.                 while (p <11) {
    377.                         for (int i = 0; i < ANT_NUMBER; ++i) {
    378.                                 if (antColony[i].flag == 1)
    379.                                         continue;
    380.                                 nextCitySelect(i, city);
    381.                                 initCity();
    382.                         }
    383.                         ++p;
    384.                 }

    385.                

    386.                 if (gen == MAX_ITERATIONS_NUMBER - 1) {
    387.                         cout << " 迭代完成,输出结果" << endl;
    388.                         printBestPath(getBestPathAntNumber(), city);

    389.                 }
    390.                
    391.                
    392.                 //更新信息素矩阵
    393.                 updatePherMartix();
    394.                 //蚁群初始化
    395.                 initAntsColony();
    396.                 pheromoneMatrix = nextPheromoneMatrix;
    397.             initMatrix(nextPheromoneMatrix, 0);
    398.                 ++gen;
    399.         }

    400. }
    401. #pragma endregion

    402. #pragma region 释放vector内存空间,避免内存无限增加而崩溃
    403. void deleArrary() {
    404.         vector<vector<double>>().swap(cityDistance);
    405.         vector<vector<double>>().swap(pheromoneMatrix);
    406.         vector<vector<double>>().swap(nextPheromoneMatrix);
    407.         vector<vector<double>>().swap(inspMartix);
    408.         //map<string, int>().swap(routResult);
    409. }
    410. #pragma endregion

    411. #pragma region 按从小到大的顺序将vec内部value值进行排序,并打印出结果
    412. void sortMap(map<string, int>t) {
    413.         //routeResult存入vec中,方便将结果进行排序
    414.         vector<pair<string, int>>vec;
    415.         for (const auto& n : t) {
    416.                 vec.push_back(make_pair(n.first, n.second));
    417.         }
    418.         //将结果按照路径,从小到达进行排序
    419.         sort(vec.begin(), vec.end(), [](const pair<string, int>& x, const pair<string, int>& y)
    420.                 -> int {
    421.                         return x.second < y.second;
    422.                 });

    423.         //输出排序好的所有结果
    424.         cout << "可供选择的路径中,从小到大为:" << endl;
    425.         int i = 1;
    426.         for (auto v : vec) {
    427.                 cout << "第" << i << "条路径为:         ";
    428.                 cout << v.first << " " << "距离为:"
    429.                         << v.second << endl;
    430.                 ++i;
    431.         }


    432.         cout << endl;
    433.         cout << "建议采纳的最佳路线为:" << vec[0].first << " "
    434.                 << "此路线距离最短,耗时最小为:"
    435.                 << vec[0].second << endl;


    436.         for (auto v : vec)
    437.         {
    438.                 if (vec[0].first.find("可充电站点") != -1) {
    439.                         break;
    440.                 }
    441.                 else if (v.first.find("可充电站点") != -1) {
    442.                         cout << "若需要中途停靠充电,建议采纳的最佳路线为:"
    443.                                 << v.first
    444.                                 << "    此路线含有充电设施,总的路径为:"
    445.                                 << v.second
    446.                                 << endl;
    447.                         break;
    448.                 }
    449.         }

    450.         t.swap(t);
    451.         vector<pair<string, int>>().swap(vec);
    452. }
    453. #pragma endregion

    454. #pragma region 程序入口

    455.         int main() {
    456.         cout << " 请输入你要去往的城市:" << endl;
    457.         int city;
    458.         cin >> city;

    459.         //不断循环迭代,将每次循环的最优结果保存到routResult中
    460.         while (1) {
    461.                 //随机化种子,用于生成随机数
    462.                 srand((unsigned)time(NULL));
    463.                 //开始进入迭代过程
    464.                 evolution(city);
    465.                 //每次迭代完成后,清空数组数据
    466.                 deleArrary();
    467.                 //判断键盘响应
    468.                 if (_kbhit()) {
    469.                         //如果读取到键盘按下'q'或'Q'键,则退出循环,结束整个过程
    470.                         if (tolower(_getch()) == 'q') {
    471.                                 break;
    472.                         }
    473.                 }
    474.         }


    475.         //int x = 20;
    476.         //while (x) {
    477.         //        //随机化种子,用于生成随机数
    478.         //        srand((unsigned)time(NULL));
    479.         //        //开始进入迭代过程
    480.         //        evolution(city);
    481.         //        //每次迭代完成后,清空数组数据
    482.         //        deleArrary();
    483.         //        --x;
    484.         //}

    485.         //将所有保存的结果按照从小到大进行排序输出,并打印出最佳结果
    486.         sortMap(routResult);
    487.         return 0;
    488. }
    489. #pragma endregion



    复制代码

     

     

     

     

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

    本版积分规则

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

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

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

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