TSP_旅行商问题-基本蚁群算法

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

TSP_旅行商问题-基本蚁群算法

旅行商系列算法

问题描述

对于n组城市坐标,寻找最短路径使其经过所有城市并回到起点。

问题数据集:tsp.eil51问题

1 37 52
2 49 49
3 52 64
4 20 26
5 40 30
6 21 47
7 17 63
8 31 62
9 52 33
10 51 21
11 42 41
12 31 32
13 5 25
14 12 42
15 36 16
16 52 41
17 27 23
18 17 33
19 13 13
20 57 58
21 62 42
22 42 57
23 16 57
24 8 52
25 7 38
26 27 68
27 30 48
28 43 67
29 58 48
30 58 27
31 37 69
32 38 46
33 46 10
34 61 33
35 62 63
36 63 69
37 32 22
38 45 35
39 59 15
40 5 6
41 10 17
42 21 10
43 5 64
44 30 15
45 39 10
46 32 39
47 25 32
48 25 55
49 48 28
50 56 37
51 30 40
最优解:426

基本蚁群算法基本流程

用一只蚂蚁的行走路径代表一个可行解;
1、确定迭代周期;
2、确定蚂蚁数;
3、对每只蚂蚁;
3.a、随机选择起点;
3.b、选择下一步;
3.b.a、根据所有与当前节点有关的路径上的信息素多少,决定下一步,一般信息素越多,选择该路径的概率越高;
3.b.b、蚂蚁有一定概率选择错误,即随机选择下一步;
3.c、选择后,在选择的路径上按照一定规则留下一定量的信息素;
3.d、最终的蚂蚁路径就是本次搜索的最佳路径;
4、等待周期结束;

基本蚁群算法在tsp问题上的应用

用一只蚂蚁的行走路径代表一个可行解,即一个城市序列;
1、确定迭代周期;
2、确定蚂蚁数;
2.a、对每只蚂蚁,随机选择起点;
2.a.a、进入循环选择后N-1个城市;
2.a.b、根据所有与当前节点城市相连的路径上的信息素多少,决定下一步,即选择信息素最多的路径;
2.a.c、蚂蚁有一定概率选择错误,即随机选择下一步要走的路径;
2.a.d、选择后,在选择的路径上按照一定规则留下一定量的信息素;
2.b、蚂蚁路径就是本次搜索的路径;
3、每群蚂蚁结束后,所有路径上的信息素进行一次衰退,保证越后进行的蚂蚁的信息素影响越大;
4、等待周期结束;

【注1】更新选择的路径上的信息素方式为为

m e s s i j = m e s s i j u + Q l e n

m e s s i j 为从第i个城市到第j个城市的路径上的信息素(初始化为该路径长度的倒数);
u 为信息素衰退因子;
Q 为常数因子;
l e n 为从起始城市回到到城市的路径距离;

【注2】更新信息素的过程分为全局更新和局部更新;
【注3】全局更新信息素的的大小有多种,以下有三种模型;

  • ACS(Ant Circle System)
    m e s s i j = m e s s i j u + Q l e n

m e s s i j 为从第i个城市到第j个城市的路径上的信息素(初始化为该路径长度的倒数);
u 为信息素衰退因子;
Q 为常数因子;
l e n 为从起始城市回到起始城市的路径距离;

  • AQS(Ant Quantity System)
    m e s s i j = m e s s i j u + Q d i c i j

m e s s i j 为从第i个城市到第j个城市的路径上的信息素(初始化为该路径长度的倒数);
u 为信息素衰退因子;
Q 为常数因子;
d i c i j 为从第i个城市到第j个城市的路径距离;

  • ADS(Ant Density System)
    m e s s i j = m e s s i j u + Q

m e s s i j 为从第i个城市到第j个城市的路径上的信息素(初始化为该路径长度的倒数);
u 为信息素衰退因子;
Q 为常数因子;

【注4】ACS模型中,每群蚂蚁只有最优的蚂蚁才能释放信息素,取消了局部更新;
【注5】个人理解:每群蚂蚁在选择路径时可以并不受当前群蚂蚁释放的信息素影响,,在每群蚂蚁结束后,再将本群蚂蚁的释放的信息素更新到全局信息素中,即只使用全局更新信息素;

参数设置

最大迭代周期 T 2500;
常数因子 Q = 1;
蚂蚁数量 ant_num = 25;
信息素衰退因子 u = 0.1;
蚂蚁选择正确概率 v = 0.9;

测试结果

当前结果
当前结果
最优解
最优结果

算法代码

#include<iostream>
#include<ctime>
#include<cmath>
#include<fstream>
#include<algorithm>
#include<string.h>
using namespace std;

typedef struct node {
    int x;
    int y;
}city;//城市节点结构体

const int num = 100;//city number
const int width = 100;//城市坐标宽度范围
const int height = 100;//城市坐标高度范围
const int Q = 1;//常数因子
const int T = 2500;//最大迭代周期
const int ant_num = 25;//蚂蚁数
const double u = 0.1;//信息素下降幅度
const double v = 0.9;//正确概率
city citys[num];//citys
double dic[num][num];//distance from two citys;
int N;//real citys
int seq[num];//最优路径序列
double answer;//最优路径长度

void init() {//set N&&x-y
    N = 51;
    citys[0].x = 37; citys[0].y = 52;
    citys[1].x = 49; citys[1].y = 49;
    citys[2].x = 52; citys[2].y = 64;
    citys[3].x = 20; citys[3].y = 26;
    citys[4].x = 40; citys[4].y = 30;
    citys[5].x = 21; citys[5].y = 47;
    citys[6].x = 17; citys[6].y = 63;
    citys[7].x = 31; citys[7].y = 62;
    citys[8].x = 52; citys[8].y = 33;
    citys[9].x = 51; citys[9].y = 21;
    citys[10].x = 42; citys[10].y = 41;
    citys[11].x = 31; citys[11].y = 32;
    citys[12].x = 5; citys[12].y = 25;
    citys[13].x = 12; citys[13].y = 42;
    citys[14].x = 36; citys[14].y = 16;
    citys[15].x = 52; citys[15].y = 41;
    citys[16].x = 27; citys[16].y = 23;
    citys[17].x = 17; citys[17].y = 33;
    citys[18].x = 13; citys[18].y = 13;
    citys[19].x = 57; citys[19].y = 58;
    citys[20].x = 62; citys[20].y = 42;
    citys[21].x = 42; citys[21].y = 57;
    citys[22].x = 16; citys[22].y = 57;
    citys[23].x = 8; citys[23].y = 52;
    citys[24].x = 7; citys[24].y = 38;
    citys[25].x = 27; citys[25].y = 68;
    citys[26].x = 30; citys[26].y = 48;
    citys[27].x = 43; citys[27].y = 67;
    citys[28].x = 58; citys[28].y = 48;
    citys[29].x = 58; citys[29].y = 27;
    citys[30].x = 37; citys[30].y = 69;
    citys[31].x = 38; citys[31].y = 46;
    citys[32].x = 46; citys[32].y = 10;
    citys[33].x = 61; citys[33].y = 33;
    citys[34].x = 62; citys[34].y = 63;
    citys[35].x = 63; citys[35].y = 69;
    citys[36].x = 32; citys[36].y = 22;
    citys[37].x = 45; citys[37].y = 35;
    citys[38].x = 59; citys[38].y = 15;
    citys[39].x = 5; citys[39].y = 6;
    citys[40].x = 10; citys[40].y = 17;
    citys[41].x = 21; citys[41].y = 10;
    citys[42].x = 5; citys[42].y = 64;
    citys[43].x = 30; citys[43].y = 15;
    citys[44].x = 39; citys[44].y = 10;
    citys[45].x = 32; citys[45].y = 39;
    citys[46].x = 25; citys[46].y = 32;
    citys[47].x = 25; citys[47].y = 55;
    citys[48].x = 48; citys[48].y = 28;
    citys[49].x = 56; citys[49].y = 37;
    citys[50].x = 30; citys[50].y = 40;
}
void set_dic() {//set distance
    for (int i = 0; i<N; ++i) {
        for (int j = 0; j<N; ++j) {
            dic[i][j] = sqrt(pow(citys[i].x - citys[j].x, 2) + pow(citys[i].y - citys[j].y, 2));
        }
    }
}
double dic_two_point(city a, city b) {
    return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2));
}
void set_mess(double conf[num][num]) {//set message
    for (int i = 0; i<N; ++i) {
        for (int j = 0; j<N; ++j) {
            conf[i][j] = Q / dic[i][j];
        }
    }
}
double count_energy(int* conf) {
    double temp = 0;
    for (int i = 1; i<N; ++i) {
        temp += dic_two_point(citys[conf[i]], citys[conf[i - 1]]);
    }
    temp += dic_two_point(citys[conf[0]], citys[conf[N - 1]]);
    return temp;
}
void output() {
    cout << "the best road is : \n";
    for (int i = 0; i < N; ++i) {
        cout << seq[i];
        if (i == N - 1)
            cout << endl;
        else
            cout << " -> ";
    }
    cout << "the length of the road is " << answer << endl;
}
void test() {

    ifstream ifile("data.txt");
    if (!ifile) {
        cout << "open field\n";
        return;
    }
    while (!ifile.eof()) {
        int te = 0;
        ifile >> te;
        ifile >> citys[te - 1].x >> citys[te - 1].y;
        N = te;
    }
}
void moni() {//每个迭代周期只有当前全局最优蚂蚁能够释放信息素
    srand(time(nullptr));

    //设定参数,初始化
    answer = 1e9;
    //set_dic();//计算距离数组
    double mess[num][num];//信息素浓度
    set_mess(mess);//设置信息素初始浓度
    int s = ant_num;

    //蚂蚁包含信息
    int visit[num];//访问数组
    int t_seq[num];//路径

    int best_seq[num];//局部最优解
    int best_ans = 1e9;
    int t = T;
    while (t--) {//迭代周期
        //memset(t_mess, 0, sizeof(t_mess));

        memset(best_seq, 0, sizeof(best_seq));
        best_ans = 1e9;

        s = ant_num;
        while (s--) {//每个蚂蚁
            //初始化每个蚂蚁;
            memset(visit, false, sizeof(visit));
            //选择起点
            int temp = rand() % N;
            t_seq[0] = temp;
            visit[temp] = 1;

            int mini = -1;
            double ans = 0;
            for (int i = 1; i < N; ++i) {//寻找最大信息素的路
                double temp = rand() % 100 / 100.0;
                if (temp>v) {//选择错误
                    int tt = rand() % N;
                    while (visit[tt]) {
                        tt = rand() % N;
                    }
                    visit[tt] = 1;
                    t_seq[i] = tt;
                    //len += dic[t_seq[i - 1]][tt];
                }
                else {
                    ans = -1;
                    mini = -1;
                    for (int j = 0; j < N; ++j) {
                        if (visit[j] == 0 && ans < mess[t_seq[i - 1]][j]) {
                            ans = mess[t_seq[i - 1]][j];
                            mini = j;
                        }
                    }
                    visit[mini] = 1;
                    t_seq[i] = mini;
                    //len += dic[t_seq[i - 1]][mini];
                }
            }
            if (count_energy(t_seq) < best_ans) {
                for (int i = 0; i < N; ++i) {
                    best_seq[i] = t_seq[i];
                }
                best_ans = count_energy(best_seq);
            }
        }
        if (count_energy(best_seq) < answer) {
            for (int i = 0; i < N; ++i) {
                seq[i] = best_seq[i];
            }
            answer = count_energy(seq);
        }

        for (int i = 0; i < N; ++i)//信息素浓度下降
            for (int j = 0; j < N; ++j) {
                mess[i][j] *= u;
                mess[i][j] += (1 - u)*Q / best_ans;
            }
    }
}

//每只蚂蚁都能释放信息素,每只蚂蚁的选择只取决于本次迭代之前的所有蚂蚁
/*void moni() {//每只蚂蚁都能释放信息素,每只蚂蚁的选择只取决于本次迭代之前的所有蚂蚁
srand(time(nullptr));
//test();//输入数据
set_dic();//计算距离数组
answer = 1e9; int t = T;
double mess[num][num];//信息素浓度
set_mess(mess);//设置信息素初始浓度
int s = ant_num;
int visit[num];
int t_seq[num];//路径
double t_mess[num][num];//信息素浓度
double len = 0;//路径长度
while (t--) {//迭代周期
memset(t_mess, 0, sizeof(t_mess));
s = ant_num;
while (s--) {//每个蚂蚁
len = 0;
//memset(visit, false, sizeof(visit));
for (int i = 0; i < N; ++i)
visit[i] = 0;
int temp = rand() % N;
t_seq[0] = temp;
visit[temp] = 1;
int mini = -1;
double ans = 0;
for (int i = 1; i < N; ++i) {//寻找最大信息素的路
double temp = rand() % 100 / 100.0;
if (temp > v) {//选择错误
int tt = rand() % N;
while (visit[tt]) {
tt = rand() % N;
}
visit[tt] = 1;
t_seq[i] = tt;
len += dic[t_seq[i - 1]][tt];
//t_mess[t_seq[i]][tt] += Q / len;
}
else {
ans = -1;
mini = -1;
for (int j = 0; j < N; ++j) {
if (visit[j] == 0 && ans < mess[t_seq[i - 1]][j]) {
ans = mess[t_seq[i - 1]][j];
mini = j;
}
}
visit[mini] = 1;
t_seq[i] = mini;
len += dic[t_seq[i - 1]][mini];
//t_mess[t_seq[i - 1]][mini] += Q /len;
}
}
t_mess[t_seq[0]][t_seq[N - 1]] += Q / len;
for (int i = 0; i < N - 1; ++i) {
t_mess[t_seq[i]][t_seq[i + 1]] += Q / len;
}
if (count_energy(t_seq) < answer) {
for (int i = 0; i < N; ++i) {
seq[i] = t_seq[i];
}
answer = count_energy(seq);
}
}

for (int i = 0; i < N; ++i)//信息素浓度下降
for (int j = 0; j < N; ++j) {
mess[i][j] *= u;
mess[i][j] += t_mess[i][j];
}
}
}*/

//每只蚂蚁都能释放信息素,每只蚂蚁的选择取决于前面的所有蚂蚁
/*void moni() {//每只蚂蚁都能释放信息素,每只蚂蚁的选择取决于前面的所有蚂蚁
srand(time(nullptr));
//test();//输入数据
set_dic();//计算距离数组
answer = 1e9;
int t = T;
double mess[num][num];//信息素浓度
set_mess(mess);//设置信息素初始浓度
int s = ant_num;
int visit[num];
int t_seq[num];//路径
//double t_mess[num][num];//信息素浓度
double len = 0;//路径长度
while (t--) {//
for (int i = 0; i < N; ++i)//信息素浓度下降
for (int j = 0; j < N; ++j) {
mess[i][j] *= u;
//mess[i][j] += t_mess[i][j];
}

//memset(t_mess, 0, sizeof(t_mess));
s = ant_num;
while (s--) {//每个蚂蚁
len = 0;
//memset(visit, false, sizeof(visit));
for (int i = 0; i < N; ++i)
visit[i] = 0;
int temp = rand() % N;
t_seq[0] = temp;
visit[temp] = 1;
int mini = -1;
double ans = 0;
for (int i = 1; i < N; ++i) {//寻找最大信息素的路
double temp = rand() % 100 / 100.0;
if (temp > v) {//选择错误
int tt = rand() % N;
while (visit[tt]) {
tt = rand() % N;
}
visit[tt] = 1;
t_seq[i] = tt;
len += dic[t_seq[i - 1]][tt];
//t_mess[t_seq[i]][tt] += Q / len;
}
else {
ans = -1;
mini = -1;
for (int j = 0; j < N; ++j) {
if (visit[j] == 0 && ans < mess[t_seq[i - 1]][j]) {
ans = mess[t_seq[i - 1]][j];
mini = j;
}
}
visit[mini] = 1;
t_seq[i] = mini;
len += dic[t_seq[i - 1]][mini];
//t_mess[t_seq[i - 1]][mini] += Q /len;
}
}
mess[t_seq[0]][t_seq[N - 1]] += Q / len;
for (int i = 0; i < N - 1; ++i) {
mess[t_seq[i]][t_seq[i + 1]] += Q / len;
}
if (count_energy(t_seq) < answer) {
for (int i = 0; i < N; ++i) {
seq[i] = t_seq[i];
}
answer = count_energy(seq);
}
}

}
}*/
int main() {
    srand(time(nullptr));
    int t;
    while (cin >> t) {//仅作为重启算法开关使用,无意义
        //init();//使用程序内置数据使用init()函数,
        test();//使用文件读取数据使用test()函数,
        set_dic();//计算每个城市之间的距离
        moni();//开始算法
        output();//输出
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wordsin/article/details/79941090