【复习档】群智能算法-蚁群算法

群智能

swarm: a large group of insects all moving together.
个体:群中的成员,之间是平等关系,没有主从关系。

群智能

个体仅具有简单智能,群体行为表现出较高级的智能。
典型的优化算法:蚁群算法、粒子群算法。还有其他的算法:鱼群算法、蜂群算法、蛙跳算法、萤火虫算法、细菌觅食算法等。

算法 大概内容 概括
蚁群优化算法 蚂蚁如何在食物源和巢穴之间找到最短路径 路径选择;信息素更新;协同工作
粒子群优化算法 鸟群随机搜索食物 个体经验;社会学习
人工鱼群算法 鱼在水域的游动 觅食行为;追尾行为;聚群行为;随机游动

蚁群优化算法-Ant Colony Optimization

背景

1991年Dorigo解决旅行商问题。改进衍生:蚁群系统,最大最小蚂蚁系统,最优保留蚁群系统。

核心

返回:蚂蚁沿着一条路到达终点后会马上返回。
信息素:信息素多表示经过这里的蚂蚁多,因而会有更多的蚂蚁聚集过来。
正反馈:某一路径上走过的蚂蚁越多,后来者选择该路径的概率越大。

基本思想

ACO实现-C++

以解决100个城市的TSP问题为例。

// ACO.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

unsigned seed = (unsigned)time(0);

//城市数目
#define CITY_NUM 100
//蚁群规模
#define ANT_NUM 150
//迭代最大次数
#define TMAX 1000

double CityPos[CITY_NUM][2] = {
{18200.0000, 109550.0000},
{18200.0000, 109583.3333},
{18206.3889, 109581.9444},
{18207.5000, 109477.7778},
{18215.8333, 109700.5556},
{18216.6667, 109700.0000},
{18220.5556, 109510.2778},
{18223.8889, 109552.2222},
{18229.7222, 109528.3333},
{18233.3333, 109533.3333},
{18233.3333, 109616.6667},
{18233.8889, 109703.8889},
{18236.6667, 109625.0000},
{18243.0556, 109505.0000},
{18243.6111, 109690.2778},
{18245.2778, 109373.8889},
{18246.6667, 109559.7222},
{18250.0000, 109516.6667},
{18250.0000, 109583.3333},
{18257.7778, 109689.4444},
{18260.5556, 109712.7778},
{18263.0556, 109580.8333},
{18263.0556, 109679.7222},
{18265.0000, 109638.6111},
{18266.6667, 109483.3333},
{18266.6667, 109566.6667},
{18266.6667, 109666.6667},
{18271.3889, 109705.8333},
{18278.3333, 109730.2778},
{18279.4444, 109675.2778},//30个
{18281.1111, 109480.8333},
{18281.3889, 109684.1667},
{18283.3333, 109400.0000},
{18283.8889, 109569.7222},
{18283.8889, 109705.5556},
{18284.4444, 109661.6667},
{18296.9444, 109611.6667},
{18302.2222, 109210.0000},
{18303.8889, 109432.2222},
{18304.1667, 109528.3333},
{18304.4444, 109335.2778},
{18304.4444, 109391.1111},
{18307.2222, 109144.1667},
{18314.7222, 109269.7222},
{18315.2778, 109626.6667},
{18316.6667, 109166.6667},
{18316.6667, 109266.6667},
{18317.2222, 109331.6667},
{18319.1667, 109442.2222},
{18319.7222, 109705.0000},//50个
{18320.2778, 109173.6111},
{18321.6667, 109551.1111},
{18325.0000, 109673.3333},
{18325.8333, 109528.3333},
{18327.2222, 109256.3889},
{18327.7778, 109247.5000},
{18332.5000, 109490.2778},
{18333.3333, 109450.0000},
{18335.2778, 109323.0556},
{18336.1111, 109731.3889},
{18344.7222, 109452.2222},
{18347.2222, 109638.8889},
{18347.7778, 109203.3333},
{18347.7778, 109587.7778},
{18349.1667, 109440.8333},
{18351.3889, 109725.8333},
{18351.3889, 109726.6667},
{18355.5556, 109627.2222},
{18356.1111, 109126.6667},
{18358.6111, 109126.3889},
{18359.1667, 108988.6111},
{18362.7778, 109602.2222},
{18370.5556, 109099.7222},
{18370.8333, 109005.5556},
{18371.6667, 109508.8889},
{18372.7778, 109163.6111},
{18374.7222, 109244.4444},
{18375.5556, 109162.2222},
{18376.1111, 109035.2778},
{18378.0556, 109603.3333},
{18378.0556, 109742.5000},
{18378.6111, 109641.6667},
{18388.3333, 109824.7222},
{18392.2222, 109725.0000},
{18393.6111, 109430.8333},
{18397.7778, 109987.5000},
{18398.6111, 109496.3889},
{18400.0000, 109730.2778},
{18400.0000, 109750.0000},
{18400.8333, 109202.7778},
{18402.2222, 109283.0556},
{18403.6111, 109020.8333},
{18403.6111, 109868.8889},
{18404.7222, 110018.6111},
{18406.6667, 109616.6667},
{18408.6111, 109758.3333},
{18409.4444, 109676.3889},
{18414.1667, 110070.2778},
{18415.8333, 108933.8889},
{18415.8333, 109725.0000}//100个
};

//alpha参数
#define ALPHA 3
//beta参数
#define BETA 4
//rho参数
#define RHO 0.4
//Q参数
#define Q 100

//地图
const int maxn = 100;
//距离矩阵
double dis[maxn][maxn];
//信息素矩阵
double info[maxn][maxn];
//启发因子矩阵
double E[maxn][maxn];
//
int vis[CITY_NUM][CITY_NUM];
//最佳结果
double BestLength;

double ans[CITY_NUM];
const double mmax = 10e9;

//产生随机整数
//指定范围
int rnd(int nLow, int nUpper)
{
    return nLow + (nUpper - nLow) * rand() / (RAND_MAX + 1);
}

//产生随机浮点数
//指定范围
double rnd(double dbLow, double dbUpper)
{
    double dbTemp = rand() / ((double)RAND_MAX + 1.0);
    return dbLow + dbTemp * (dbUpper - dbLow);
}

//浮点数取整
//四舍五入
double ROUND(double dbA)
{
    return (double)((int)(dbA + 0.5));
}


//ant
struct Ant
{
    //蚂蚁走的路线,时间顺序,存放内容是“第i步到了哪个城市”
    int Path[CITY_NUM];
    //路径的总长度
    double length;
    //标记走过的城市,城市标记表,如果走过了记为1,否则都是0
    int vis[CITY_NUM];
    //当前所处的城市编号
    int cur_cityno;
    //已走城市的数量,会累加
    int moved_cnt;

    //初始化函数
    void Init()
    {
        //开辟空间
        memset(vis, 0, sizeof(vis));
        //路径总长度初始化为0
        length = 0;
        //随便定一个起始城市
        cur_cityno = rnd(0, CITY_NUM);
        //路线记录的第一个城市设为刚才random出来的城市
        Path[0] = cur_cityno;
        //在记录城市是否已经走过的数组中标记刚才random出来的城市为1
        vis[cur_cityno] = 1;
        //已经走了一个城市
        moved_cnt = 1;
    }

    //选择路径
    //求出蚂蚁要走的下一个城市的编号为多少
    int chooseNextCity()
    {
        //返回的城市编号
        //初始化设置为-1(后续再进行改变)
        int nSelectedCity = -1;
        //计算当前城市和没去过的城市之间的信息素总量
        double dbTotal = 0.0;
        //数组
        //存放城市被选中的概率,也就是公式中的pk(i,j)中分子的部分
        double prob[CITY_NUM];

        //转换公式
        //对于每个城市而言
        for (int i = 0; i < CITY_NUM; i++)
        {
            //如果一直以来都没有访问过编号为i的城市
            if (!vis[i])
            {
                //求分子
                prob[i] = pow(info[cur_cityno][i], ALPHA) * pow(1.0 / dis[cur_cityno][i], BETA);

                dbTotal = dbTotal + prob[i];
            }
            else
            {
                prob[i] = 0;
            }
        }

        //轮盘赌选择
        double dbTemp = 0.0;
        //如果总的信息素值大于0
        if (dbTotal > 0.0)
        {
            //在0和信息素总含量中随机生成一个阈值
            dbTemp = rnd(0.0, dbTotal);
            for (int i = 0; i < CITY_NUM; i++)
            {
                if (!vis[i])
                {
                    //作差
                    dbTemp = dbTemp - prob[i];
                    //如果该城市的信息素含量超过随机生成的阈值大小
                    if (dbTemp < 0.0)
                    {
                        //那么选择该城市
                        nSelectedCity = i;
                        //跳出循环
                        break;
                    }
                }
            }
        }
        //如果经过轮盘赌还是没选出下一步走哪个城市
        if (nSelectedCity == -1)
        {
            //在所有城市当中选出第一个没去过的城市作为下一步要去的城市
            for (int i = 0; i < CITY_NUM; i++)
            {
                //遇到第一个没有被访问的城市
                if (!vis[i])
                {
                    //选择该城市
                    nSelectedCity = i;
                    //跳出循环
                    break;
                }
            }
        }
        return nSelectedCity;
    }
    //蚂蚁移动
    void Move()
    {
        //首先找到接下来要去哪个城市
        int nCityno = chooseNextCity();
        //蚂蚁下一步要走这个城市
        Path[moved_cnt] = nCityno;
        //蚂蚁即将经历这个城市
        vis[nCityno] = 1;
        //目前到达这个城市
        cur_cityno = nCityno;
        //蚂蚁的总路线登记累加move的距离
        length = length + dis[Path[moved_cnt - 1]][Path[moved_cnt]];
        moved_cnt++;
    }
    //蚂蚁搜索----总流程
    void Search()
    {
        //先初始化一只蚂蚁
        Init();
        //蚂蚁在地图上走
        while (moved_cnt < CITY_NUM)
        {
            Move();
        }
        //补上终点和起点的路径长度
        length = length + dis[Path[CITY_NUM - 1]][Path[0]];
    }
};

struct TSP
{
    //数组
    //存放一群蚂蚁
    Ant ants[ANT_NUM];
    //记录最好结果的蚂蚁信息
    Ant ant_best;
    void Init()
    {
        //初始设置这群蚂蚁中最好的距离是一个超大值
        //等待迭代后进行更新
        ant_best.length = mmax;

        //初始化城市间距离矩阵
        //遍历计算,邻接矩阵存放城市之间的欧式距离
        //dis二维数组
        for (int i = 0; i < CITY_NUM; i++)
        {
            for (int j = 0; j < CITY_NUM; 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);
            }
        }

        //初始化信息素
        //info二维数组
        for (int i = 0; i < CITY_NUM; i++)
        {
            for (int j = 0; j < CITY_NUM; j++)
            {
                info[i][j] = 1.0;
            }
        }
    }

    //信息素矩阵更新
    void Updateinfo()
    {
        //信息素增量矩阵
        double tmpinfo[CITY_NUM][CITY_NUM];
        //
        memset(tmpinfo, 0, sizeof(tmpinfo));
        //城市m,初始值设为0
        int m = 0;
        //城市n,初始值设为0
        int n = 0;
        //
        for (int i = 0; i < ANT_NUM; i++)
        {
            //从第一个城市到最后一个城市
            for (int j = 1; j < CITY_NUM; j++)
            {
                m = ants[i].Path[j];
                n = ants[i].Path[j - 1];

                //计算信息素增量
                tmpinfo[n][m] = tmpinfo[n][m] + Q / ants[i].length;
                //保持信息素增量矩阵的对称性
                tmpinfo[m][n] = tmpinfo[n][m];
            }
            //最后一个城市到第一个城市
            n = ants[i].Path[0];
            //计算信息素增量
            tmpinfo[n][m] = tmpinfo[n][m] + Q / ants[i].length;
            //保持信息素增量矩阵的对称性
            tmpinfo[m][n] = tmpinfo[n][m];
        }
        //原信息素矩阵耗散后的值加上信息素增量矩阵对应的值
        for (int i = 0; i < CITY_NUM; i++)
        {
            for (int j = 0; j < CITY_NUM; j++)
            {
                info[i][j] = info[i][j] * RHO + tmpinfo[i][j];
            }
        }
    }
    //寻找路径----总流程
    void Search()
    {
        //进行TMAX次循环
        //里面是每次循环的内容
        for (int i = 0; i < TMAX; i++)
        {
            cout << "当前循环次数为" << i << endl;
            //对于当前设定的种族中的所有蚂蚁而言,都开始分别进行路线搜索
            //并且完成一次搜索
            for (int j = 0; j < ANT_NUM; j++)
            {
                ants[j].Search();
            }
            //记录最优结果
            for (int j = 0; j < ANT_NUM; j++)
            {
                //希望找到最短距离
                if (ant_best.length > ants[j].length)
                {
                    //更新
                    ant_best = ants[j];
                }
            }
            //更新信息素
            Updateinfo();
            cout << "目前得到的最短路径长度为" << ant_best.length << endl;
        }
    }
};



int main()
{
    srand(seed);
    TSP tsp;
    tsp.Init();
    tsp.Search();
    cout << "最短路径为" << endl;
    for (int i = 0; i < CITY_NUM; i++)
    {
        cout << tsp.ant_best.Path[i] << endl;
    }
    return 0;
}

// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
// Debug program: F5 or Debug > Start Debugging menu

// Tips for Getting Started: 
//   1. Use the Solution Explorer window to add/manage files
//   2. Use the Team Explorer window to connect to source control
//   3. Use the Output window to see build output and other messages
//   4. Use the Error List window to view errors
//   5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
//   6. In the future, to open this project again, go to File > Open > Project and select the .sln file

你可能感兴趣的:(算法,人工智能)