自然启发的搜索算法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Travis_X/article/details/86568639

旅行商问题(TSP):一个销售员要要访问n座城市,从某座城市出发,在任意两座城市可以计算距离的前提下,希望以最短路径把每座城市都访问一遍并最终回到出发的城市。

TSP通常引入模拟退火算法遗传算法蚁群算法来解决。 

模拟退火算法

实现流程:

模æéç«ç®æ³çåçãä¼ç¼ºç¹ãæµç¨ãåºç¨å®ä¾

实现代码:

/*
 * 使用模拟退火算法(SA)求解TSP问题(以中国TSP问题为例)
 * 参考自《Matlab 智能算法30个案例分析》
 * 模拟退火的原理这里略去,可以参考上书或者相关论文
 * update: 16/12/11
 * author:lyrichu
 * email:[email protected]
 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<math.h>
#define T0 50000.0  // 初始温度
#define T_end (1e-8)
#define q  0.98   // 退火系数
#define L 1000  // 每个温度时的迭代次数,即链长
#define N 31  // 城市数量
int city_list[N]; // 用于存放一个解
double city_pos[N][2] = {{1304,2312},{3639,1315},{4177,2244},{3712,1399},{3488,1535},{3326,1556},{3238,1229},{4196,1004},{4312,790},
    {4386,570},{3007,1970},{2562,1756},{2788,1491},{2381,1676},{1332,695},{3715,1678},{3918,2179},{4061,2370},{3780,2212},{3676,2578},{4029,2838},
    {4263,2931},{3429,1908},{3507,2367},{3394,2643},{3439,3201},{2935,3240},{3140,3550},{2545,2357},{2778,2826},{2370,2975}}; // 中国31个城市坐标
//函数声明
double distance(double *,double *); // 计算两个城市距离
double path_len(int *);  // 计算路径长度
void  init();  //初始化函数
void create_new(); // 产生新解
// 距离函数
double distance(double * city1,double * city2)
{
    double x1 = *city1;
    double y1 = *(city1+1);
    double x2 = *(city2);
    double y2 = *(city2+1);
    double dis = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    return dis;
}

// 计算路径长度
double path_len(int * arr)
{
    double path = 0; // 初始化路径长度
    int index = *arr; // 定位到第一个数字(城市序号)
    for(int i=0;i<N-1;i++)
    {
        int index1 = *(arr+i);
        int index2 = *(arr+i+1);
        double dis = distance(city_pos[index1-1],city_pos[index2-1]);
        path += dis;
    }
    int last_index = *(arr+N-1); // 最后一个城市序号
    int first_index = *arr; // 第一个城市序号
    double last_dis = distance(city_pos[last_index-1],city_pos[first_index-1]);
    path = path + last_dis;
    return path; // 返回总的路径长度
}

// 初始化函数
void init()
{
    for(int i=0;i<N;i++)
        city_list[i] = i+1;  // 初始化一个解
}

// 产生一个新解
// 此处采用随机交叉两个位置的方式产生新的解
void create_new()
{
    double r1 = ((double)rand())/(RAND_MAX+1.0);
    double r2 = ((double)rand())/(RAND_MAX+1.0);
    int pos1 = (int)(N*r1); //第一个交叉点的位置
    int pos2 = (int)(N*r2);
    int temp = city_list[pos1];
    city_list[pos1] = city_list[pos2];
    city_list[pos2] = temp;   // 交换两个点
}

// 主函数
int main(void)
{
    srand((unsigned)time(NULL)); //初始化随机数种子
    time_t start,finish;
    start = clock(); // 程序运行开始计时
    double T;
    int count = 0; // 记录降温次数
    T = T0; //初始温度
    init(); //初始化一个解
    int city_list_copy[N]; // 用于保存原始解
    double f1,f2,df; //f1为初始解目标函数值,f2为新解目标函数值,df为二者差值
    double r; // 0-1之间的随机数,用来决定是否接受新解
    while(T > T_end) // 当温度低于结束温度时,退火结束
    {
        for(int i=0;i<L;i++)
        {
            memcpy(city_list_copy,city_list,N*sizeof(int)); // 复制数组
            create_new(); // 产生新解
            f1 = path_len(city_list_copy);
            f2 = path_len(city_list);
            df = f2 - f1;
            // 以下是Metropolis准则
            if(df >= 0)
            {
                r = ((double)rand())/(RAND_MAX);
                if(exp(-df/T) <= r) // 保留原来的解
                {
                    memcpy(city_list,city_list_copy,N*sizeof(int));
                }
            }
        }
        T *= q; // 降温
        count++;
    }
    finish = clock(); // 退火过程结束
    double duration = ((double)(finish-start))/CLOCKS_PER_SEC; // 计算时间
    printf("采用模拟退火算法,初始温度T0=%.2f,降温系数q=%.2f,每个温度迭代%d次,共降温%d次,得到的TSP最优路径为:\n",T0,q,L,count);
    for(int i=0;i<N-1;i++)  // 输出最优路径
    {
        printf("%d--->",city_list[i]);
    }
    printf("%d\n",city_list[N-1]);
    double len = path_len(city_list); // 最优路径长度
    printf("最优路径长度为:%lf\n",len);
    printf("程序运行耗时:%lf秒.\n",duration);
    return 0;
}

 

遗传算法

实现流程:

è¿éåå¾çæè¿°

/*
 *遗传算法(GA) 解决TSP 问题
 *案例参考自《MATLAB 智能算法30个案例分析》
 *本例以14个城市为例,14个城市的位置坐标如下(括号内第一个元素为X坐标,第二个为纵坐标):1:(16.47,96.10)  2:(16.47,94.44)  3:(20.09,92.54)
 *4:(22.39,93.37) 5:(25.23,97.24)  6:(22.00,96.05) 7:(20.47,97.02)  8:(17.20,96.29) 9:(16.30,97.38) 10:(14.05,98.12) 11:(16.53,97.38)
 *12:(21.52,95.59)  13:(19.41,97.13)  14:(20.09,92.55)
 *遗传算法实现的步骤为:(1)编码 (2) 种群初始化 (3) 构造适应度函数 (4) 选择操作 (5) 交叉操作 (6) 变异操作 (7) 进化逆转操作
 * 具体实现的步骤这里不详细说,参考《MATLAB 智能算法30个案例分析》P38 - P40
 * update in 16/12/4
 * author:Lyrichu
 * email:[email protected]
 */
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
#define maxgen 200  // 最大进化代数
#define sizepop 100 // 种群数目
#define pcross 0.6 // 交叉概率
#define pmutation 0.1 // 变异概率
#define lenchrom 14 // 染色体长度(这里即为城市个数)
double city_pos[lenchrom][2] = {{16.47,96.10},{16.47,94.44},{20.09,92.54},{22.39,93.37},{25.23,97.24},{22.00,96.05},{20.47,97.02},
    {17.20,96.29},{16.30,97.38},{14.05,98.12},{16.53,97.38},{21.52,95.59},{19.41,97.13},{20.09,92.55}}; // 定义二维数组存放14个城市的X、Y坐标
int chrom[sizepop][lenchrom]; // 种群
int best_result[lenchrom]; // 最佳路线
double min_distance; // 最短路径长度

// 函数声明
void init(void); // 种群初始化函数
double distance(double *,double *); // 计算两个城市之间的距离
double * min(double *); // 计算距离数组的最小值
double path_len(int *); // 计算某一个方案的路径长度,适应度函数为路线长度的倒数
void Choice(int [sizepop][lenchrom]); // 选择操作
void Cross(int [sizepop][lenchrom]); // 交叉操作
void Mutation(int [sizepop][lenchrom]); // 变异操作
void Reverse(int [sizepop][lenchrom]); // 逆转操作

// 种群初始化
void init(void)
{
    int num = 0;
    while(num < sizepop)
    {
        for(int i=0;i<sizepop;i++)
            for(int j=0;j<lenchrom;j++)
                chrom[i][j] = j+1;
        num++;
        for(int i=0;i<lenchrom-1;i++)
        {
            for(int j=i+1;j<lenchrom;j++)
            {
                int temp = chrom[num][i];
                chrom[num][i] = chrom[num][j];
                chrom[num][j] = temp; // 交换第num个个体的第i个元素和第j个元素
                num++;
                if(num >= sizepop)
                    break;
            }
            if(num >= sizepop)
                break;
        }
        // 如果经过上面的循环还是无法产生足够的初始个体,则随机再补充一部分
        // 具体方式就是选择两个基因位置,然后交换
        while(num < sizepop)
        {
            double r1 = ((double)rand())/(RAND_MAX+1.0);
            double r2 = ((double)rand())/(RAND_MAX+1.0);
            int p1 = (int)(lenchrom*r1); // 位置1
            int p2 = (int)(lenchrom*r2); // 位置2
            int temp = chrom[num][p1];
            chrom[num][p1] = chrom[num][p2];
            chrom[num][p2] = temp;    // 交换基因位置
            num++;
        }
    }
}

// 距离函数
double distance(double * city1,double * city2)
{
    double x1 = *city1;
    double y1 = *(city1+1);
    double x2 = *(city2);
    double y2 = *(city2+1);
    double dis = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    return dis;
}
// min()函数
double * min(double * arr)
{
    static double best_index[2];
    double min_dis = *arr;
    double min_index = 0;
    for(int i=1;i<sizepop;i++)
    {
        double dis = *(arr+i);
        if(dis < min_dis)
        {
            min_dis = dis;
            min_index = i;
        }
    }
    best_index[0] = min_index;
    best_index[1] = min_dis;
    return best_index;
}

// 计算路径长度
double path_len(int * arr)
{
    double path = 0; // 初始化路径长度
    int index = *arr; // 定位到第一个数字(城市序号)
    for(int i=0;i<lenchrom-1;i++)
    {
        int index1 = *(arr+i);
        int index2 = *(arr+i+1);
        double dis = distance(city_pos[index1-1],city_pos[index2-1]);
        path += dis;
    }
    int last_index = *(arr+lenchrom-1); // 最后一个城市序号
    int first_index = *arr; // 第一个城市序号
    double last_dis = distance(city_pos[last_index-1],city_pos[first_index-1]);
    path = path + last_dis;
    return path; // 返回总的路径长度
}

// 选择操作
void Choice(int chrom[sizepop][lenchrom])
{
    double pick;
    double choice_arr[sizepop][lenchrom];
    double fit_pro[sizepop];
    double sum = 0;
    double fit[sizepop]; // 适应度函数数组(距离的倒数)
    for(int j=0;j<sizepop;j++)
    {
        double path = path_len(chrom[j]);
        double fitness = 1/path;
        fit[j] = fitness;
        sum += fitness;
    }
    for(int j=0;j<sizepop;j++)
    {
        fit_pro[j] = fit[j]/sum; // 概率数组
    }
    // 开始轮盘赌
    for(int i=0;i<sizepop;i++)
    {
        pick = ((double)rand())/RAND_MAX; // 0到1之间的随机数  
        for(int j=0;j<sizepop;j++)
        {
            pick = pick - fit_pro[j];
            if(pick<=0)
            {
                for(int k=0;k<lenchrom;k++)
                    choice_arr[i][k] = chrom[j][k]; // 选中一个个体
                break;    
            }
        }

    }
    for(int i=0;i<sizepop;i++)
    {
        for(int j=0;j<lenchrom;j++)
            chrom[i][j] = choice_arr[i][j];
    }
}

//交叉操作
void Cross(int chrom[sizepop][lenchrom])
{
    double pick;
    double pick1,pick2;
    int choice1,choice2;
    int pos1,pos2;
    int temp;
    int conflict1[lenchrom]; // 冲突位置
    int conflict2[lenchrom];
    int num1,num2;
    int index1,index2;
    int move = 0; // 当前移动的位置
    while(move<lenchrom-1)
    {
        pick = ((double)rand())/RAND_MAX; // 用于决定是否进行交叉操作
        if(pick > pcross)
        {
            move += 2;
            continue; // 本次不进行交叉
        }
        // 采用部分映射杂交
        choice1 = move; // 用于选取杂交的两个父代
        choice2 = move+1; // 注意避免下标越界
        pick1 = ((double)rand())/(RAND_MAX+1.0);
        pick2 = ((double)rand())/(RAND_MAX+1.0);
        pos1 = (int)(pick1*lenchrom); // 用于确定两个杂交点的位置
        pos2 = (int)(pick2*lenchrom); 
        while(pos1 > lenchrom -2 || pos1 < 1)
        {
            pick1 = ((double)rand())/(RAND_MAX+1.0);
            pos1 = (int)(pick1*lenchrom);
        }
        while(pos2 > lenchrom -2 || pos2 < 1)
        {
            pick2 = ((double)rand())/(RAND_MAX+1.0);
            pos2 = (int)(pick2*lenchrom);
        }
        if(pos1 > pos2)
        {
            temp = pos1;
            pos1 = pos2;
            pos2 = temp; // 交换pos1和pos2的位置
        }
        for(int j=pos1;j<=pos2;j++)
        {
            temp = chrom[choice1][j];
            chrom[choice1][j] = chrom[choice2][j];
            chrom[choice2][j] = temp; // 逐个交换顺序
        }
        num1 = 0;
        num2 = 0;
        if(pos1 > 0 && pos2 < lenchrom-1)
        {
            for(int j =0;j<=pos1-1;j++)
            {
                for(int k=pos1;k<=pos2;k++)
                {
                    if(chrom[choice1][j] == chrom[choice1][k])
                    {
                        conflict1[num1] = j;
                        num1++;
                    }
                    if(chrom[choice2][j] == chrom[choice2][k])
                    {
                        conflict2[num2] = j;
                        num2++;
                    }
                }
            }
            for(int j=pos2+1;j<lenchrom;j++)
            {
                for(int k=pos1;k<=pos2;k++)
                {
                    if(chrom[choice1][j] == chrom[choice1][k])
                    {
                        conflict1[num1] = j;
                        num1++;
                    }
                    if(chrom[choice2][j] == chrom[choice2][k])
                    {
                        conflict2[num2] = j;
                        num2++;                     
                    }                 
                }

            }
        }
        if((num1 == num2) && num1 > 0)
        {
            for(int j=0;j<num1;j++)
            {
                index1 = conflict1[j];
                index2 = conflict2[j];
                temp = chrom[choice1][index1]; // 交换冲突的位置
                chrom[choice1][index1] = chrom[choice2][index2];
                chrom[choice2][index2] = temp;
            }
        }
        move += 2;
    }
}

// 变异操作
// 变异策略采取随机选取两个点,将其对换位置
void Mutation(int chrom[sizepop][lenchrom])
{
    double pick,pick1,pick2;
    int pos1,pos2,temp;
    for(int i=0;i<sizepop;i++)
    {
         pick = ((double)rand())/RAND_MAX; // 用于判断是否进行变异操作
        if(pick > pmutation)
            continue;
        pick1 = ((double)rand())/(RAND_MAX+1.0);
        pick2 = ((double)rand())/(RAND_MAX+1.0);
        pos1 = (int)(pick1*lenchrom); // 选取进行变异的位置
        pos2 = (int)(pick2*lenchrom);
        while(pos1 > lenchrom-1)
        {
            pick1 = ((double)rand())/(RAND_MAX+1.0);
            pos1 = (int)(pick1*lenchrom);
        }
        while(pos2 > lenchrom-1)
        {
            pick2 = ((double)rand())/(RAND_MAX+1.0);
            pos2 = (int)(pick2*lenchrom);
        }
        temp = chrom[i][pos1];
        chrom[i][pos1] = chrom[i][pos2];
        chrom[i][pos2] = temp;
    }
}

// 进化逆转操作
void Reverse(int chrom[sizepop][lenchrom])
{
    double pick1,pick2;
    double dis,reverse_dis;
    int n;
    int flag,pos1,pos2,temp;
    int reverse_arr[lenchrom];
    
    for(int i=0;i<sizepop;i++)
    {
        flag = 0; // 用于控制本次逆转是否有效
        while(flag == 0)
        {
            pick1 = ((double)rand())/(RAND_MAX+1.0);
            pick2 = ((double)rand())/(RAND_MAX+1.0);
            pos1 = (int)(pick1*lenchrom); // 选取进行逆转操作的位置
            pos2 = (int)(pick2*lenchrom);
            while(pos1 > lenchrom-1)
            {
                pick1 = ((double)rand())/(RAND_MAX+1.0);
                pos1 = (int)(pick1*lenchrom);
            }
            while(pos2 > lenchrom -1)
            {
                pick2 = ((double)rand())/(RAND_MAX+1.0);
                pos2 = (int)(pick2*lenchrom);
            }
            if(pos1 > pos2)
            {
                temp = pos1;
                pos1 = pos2;
                pos2 = temp; // 交换使得pos1 <= pos2
            }
            if(pos1 < pos2)
            {
                for(int j=0;j<lenchrom;j++)
                    reverse_arr[j] = chrom[i][j]; // 复制数组
                n = 0; // 逆转数目
                for(int j=pos1;j<=pos2;j++)
                {
                    reverse_arr[j] = chrom[i][pos2-n]; // 逆转数组
                    n++; 
                }
                reverse_dis = path_len(reverse_arr); // 逆转之后的距离
                dis = path_len(chrom[i]); // 原始距离
                if(reverse_dis < dis)
                {
                    for(int j=0;j<lenchrom;j++)
                        chrom[i][j] = reverse_arr[j]; // 更新个体
                }
            }
            flag = 1;
        }    

    }   
}

// 主函数
int main(void)
{
    time_t start,finish;
    start = clock(); // 开始计时
    srand((unsigned)time(NULL)); // 初始化随机数种子
    init(); // 初始化种群

    int best_fit_index = 0; //最短路径出现代数
    double distance_arr[sizepop];
    double dis;
    for(int j=0;j<sizepop;j++)
    {
        dis = path_len(chrom[j]);
        distance_arr[j] = dis;
    }
    double * best_index = min(distance_arr); // 计算最短路径及序号
    min_distance = *(best_index+1); // 最短路径
    int index = (int)(*best_index); // 最短路径序号
    for(int j=0;j<lenchrom;j++)
        best_result[j] = chrom[index][j]; // 最短路径序列

    // 开始进化
    double * new_arr;
    double new_min_dis;
    int new_index;
    for(int i=0;i<maxgen;i++) 
    {
        Choice(chrom); // 选择
        Cross(chrom); //交叉
        Mutation(chrom); //变异
        Reverse(chrom); // 逆转操作
        for(int j=0;j<sizepop;j++)
            distance_arr[j] = path_len(chrom[j]); // 距离数组
        new_arr = min(distance_arr);
        new_min_dis = *(new_arr+1); //新的最短路径
        if(new_min_dis < min_distance)
        {
            min_distance = new_min_dis; // 更新最短路径
            new_index =(int)(*new_arr);
            for(int j=0;j<lenchrom;j++)
                best_result[j] = chrom[new_index][j]; // 更新最短路径序列
            best_fit_index = i+1; // 最短路径代数
        }
    }
finish = clock(); // 计算结束
double duration = ((double)(finish-start))/CLOCKS_PER_SEC; // 计算耗时
printf("本程序使用遗传算法求解规模为%d的TSP问题,种群数目为:%d,进化代数为:%d\n",lenchrom,sizepop,maxgen);
printf("得到最短路径为:%d-->%d-->%d-->%d-->%d-->%d-->%d-->%d-->%d-->%d-->%d-->%d-->%d-->%d\n",best_result[0],best_result[1],best_result[2],
        best_result[3],best_result[4],best_result[5],best_result[6],best_result[7],best_result[8],best_result[9],best_result[10],best_result[11],
        best_result[12],best_result[13]);
printf("最短路径长度为:%lf,得到最短路径在第%d代.\n",min_distance,best_fit_index);
printf("程序耗时:%lf秒.\n",duration);
return 0;
}

蚁群算法

实现流程:

#include<iostream>
#include<cmath>
using namespace std;
//使用10个蚂蚁,进行10个城市的TSP问题求解。
const int MMax = 9999;//蚂蚁数量,蚂蚁数量根据城市数量决定。
const int NMax = 500;//城市数量最大数量,超过出错
const int m=999;//蚂蚁数量
const int n=5;//城市数量
const double Q = 9 ;//常量
const int K = 1000;//循环总次数
double Phe[NMax][NMax];//边对应的信息素浓度
int LK;//蚂蚁此循环中的总路径长度
int Path[MMax][NMax];//记录蚂蚁的路径,用于防止走重复的路。记录的是点
int ant;//蚂蚁当前所在点
int i,j,k,p;//循环使用
double Dis = 0.1;//每次信息素 消失的速率
int sameNum,samePhe[NMax];//每次去寻找信息素最多的边,如初始情况,信息素量都相同时,要
//随机的去从中选取边。
int bugNum,bugTry[NMax];//出错情况下进行的选择
double bugP = 0.90;//每一次操作的出错概率
//后来发现,出错概率要结合蚂蚁数与城市数进行判断,而定值Q为估计距离
int start=0;//出发点,城市编号从0 - n-1.
double Max;//用来选取最多信息素的边
bool Passed[NMax];//用来判断城市是否已经经过,是否可以选取
const int inf = 9999;
double D[n][n];
//double city_pos[n][2] = {{0,0},{1,0},{2,0},{3,0},{0,1},{1,1},{2,1},{3,1},{0,2},{1,2},{2,2},{3,2},{0,3},{1,3},{2,3},{3,3}}; // 定义二维数组存放16个城市的X、Y坐标
double city_pos[n][2] = {{0,0},{4,1},{3,3},{1,4},{0,2}};//定义二维数组存放n个城市的X、Y坐标
/*int D[9][9]={
              0,   1, inf,   1, inf, inf, inf, inf, inf,
              1,   0,   1, inf,   1, inf, inf, inf, inf,
            inf,   1,   0, inf, inf,   1, inf, inf, inf,
              1, inf, inf,   0,   1, inf,   1, inf, inf,
            inf,   1, inf,   1,   0,   1, inf,   1, inf,
            inf, inf,   1, inf,   1,   0, inf, inf,   1,
            inf, inf, inf,   1, inf, inf,   0,   1, inf,
            inf, inf, inf, inf,   1, inf,   1,   0,   1,
            inf, inf, inf, inf, inf,   1, inf,   1,   0
};*/

/********************************距离函数********************************/
double distance(double * city1,double * city2)
{
    double x1 = *city1;
    double y1 = *(city1+1);
    double x2 = *(city2);
    double y2 = *(city2+1);
    //double dis = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));//欧氏距离
	double dis = fabs(x1-x2)+fabs(y1-y2);//曼哈顿距离
    return dis;
}


/********************************主函数********************************/
int main()
{
   //生成距离矩阵
   for(int i=0;i<n;i++)
    {
		for(int j=0;j<n;j++)
		{	
			if(i!=j)
			{double dis = distance(city_pos[i],city_pos[j]);D[i][j]=dis;}
			else
				D[i][j]=1e-4;
		}
	}
	//初始化每条边上的信息素浓度,初始时每条边上的信息素浓度相同
	for(i = 0;i < n;i++)
		for(j = 0; j < n;j++) 
			Phe[i][j] = 1;
	//每只蚂蚁的出发点都固定
	for(i = 0;i< m;i++)
		Path[i][0] = start;

	for(k = 0;k < K;k++){
		//每次循环后,进行信息素的消逝
		for(i = 0;i < n;i++)
			for(j = 0; j < n;j++) 
				Phe[i][j] *= Dis ;
		srand((unsigned)time(NULL)); 
		for(i = 0;i < m;i++){//对于每只蚂蚁,进行一次循环	
			ant = start;//蚂蚁当前所在城市
			//初始化蚂蚁经过路径
			for(j = 0;j < n;j++)
				Passed[j] = false;//蚂蚁未经过路径
			Passed[ant] = true;//蚂蚁出发时经过路径
			for(j = 1;j < n;j++){//每只蚂蚁选n-1次边
				Max = 0;
				sameNum  = 0 ;
				bugNum = 0;
				for(p = 0;p < n;p++)
					if(!Passed[p])
						Max = Max > Phe[ant][p] ? Max : Phe[ant][p] ;//寻找周围边上信息素的最大值
				for(p = 0;p < n;p++)
					if(Max == Phe[ant][p])
						if(!Passed[p])
							samePhe[sameNum++] = p;//记录信息素取最大值时,对应的city编号和数量
				for(p = 0;p < n;p++)
					if(!Passed[p])
						bugTry[bugNum++] = p;//记录出错情况下,对应的city编号和数量
				if( (double)rand() /32765 < bugP)
					ant = samePhe[ rand() % sameNum ] ;//用随机数,从中选中一条边
				else
					ant = bugTry [ rand() % bugNum ] ;//出错情况下,随机选一条边
				Passed[ant] = true;//路径经过
				Path[i][j] = ant;//保存路径
			}
		}
		//完成对每一个蚂蚁的操作后,进行增加信息素的操作,使用Ant-Circle System模型
		for(i = 0; i < m;i++){
			LK  = 0 ;
			for(j = 0; j < n-1;j++)
				LK += D[Path[i][j]][Path[i][j+1]];//计算每一次循环中蚂蚁的总路程
			LK += D[Path[i][j]][Path[i][0]];//回到初始点
			for(j = 0; j < n-1;j++)
				Phe[Path[i][j]][Path[i][j+1]] += Q/LK ;//边对应的信息素浓度之和
			Phe[Path[i][j]][Path[i][0]] += Q/LK ;//初始点边对应的信息素浓度
		}
	}
	p = 0xfffff;//虽然已经完成操作,但我们要直观的从所有现有路径中找出最短的路径。
	for(i = 0;i < m;i++){
		LK = 0;
		for(j = 0;j < n-1;j++)
			LK += D[Path[i][j]][Path[i][j+1]];//计算一次循环中蚂蚁的总路程
		LK += D[Path[i][j]][Path[i][0]];//回到初始点
		if(LK < p){
			p = LK;
			start = i;
		}
	}
	for(i = 0;i < n; i++)
		cout << Path[start][i]+1<<"->";
	cout << Path[start][0]+1<<endl;
	return 0;
}

三种算法的优缺点对比

算法

优势

不足

模拟退火算法 有限度接受劣值,可求解非线性问题,鲁棒性强。 运算速度慢,挠动机制种类繁多,易遗失当前最优解。
遗传算法 具备并行搜索特性,且不受函数约束条件限制、全局搜索性能较强、获得局部最优的概率较低。 计算量较大,占用存储空间存储空间较多。
蚁群算法 编程简单、鲁棒性强、易于与其他算法结合、并行性好、适用领域广泛。 搜索速度有待提高,且容易停滞而得到局部最优。

参考资料:

https://www.cnblogs.com/lyrichu/p/6688459.html

https://www.cnblogs.com/lyrichu/p/6152928.html

https://blog.csdn.net/shelldawn/article/details/80613132

https://www.cnblogs.com/8335IT/p/5635892.html

吴慧超,《基于ROS的多AGV多目标点导航系统研究及实现》

猜你喜欢

转载自blog.csdn.net/Travis_X/article/details/86568639