TSP_旅行商问题-遗传算法

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

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、开始循环;
2.a、选择,计算种群中每个个体的适应值,根据适应值选择出新的种群替换原来的种群,使得适应值越大的个体被保留下来的可能越大;
2.b、交叉,将种群中的个体两两相邻组合,对每对个体都有一定的交叉概率,使得其交叉互换部分,产生新的两个个体,替换源个体;
2.c、变异,对种群中的每个个体,都有一定的变异概率,使该个体的部分变异;
3、退出循环体,新种群中的最优解达到目标;

遗传算法在tsp问题上的应用流程

1、初始化种群,随机产生多组可行解;
2、开始循环;
2.a、选择,计算种群中每个个体的适应值,根据适应值选择出新的种群替换原来的种群,使得适应值越大的个体被保留下来的可能越大;
2.b、交叉,将种群中的个体两两相邻组合,对每对个体都有一定的交叉概率,使得其交叉互换相同长度的部分城市序列,产生新的两个个体,合法化后替换源个体;
2.c、变异,对种群中的每个个体即每个序列,都有一定的变异概率,使该个体的部分变异,即随机选择序列中的两个城市,交换其顺序;
3、退出循环体,迭代次数控制循环结束;
【注1】适应值为路径总长的倒数;
【注2】交叉部分可能会产生不合法的后代,所以需要用函数处理一下,使其合法,即路径中不存在重复节点;

参数设置

种群数量 pop_size = 300;
变异概率 u = 0.1;
交叉概率 v = 0.9;
迭代次数 k = 1000;

测试结果

当前结果
最优解

算法代码

#include<iostream>
#include<ctime>
#include<cmath>
#include<fstream>
#include<algorithm>
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 pop_size = 300;//种群大小
int seq_pop[pop_size][num];//种群
double energy[pop_size];//个体能量
double fitness[pop_size];//适应度
double sum_fitness = 0;
double sum_energy = 0;//总能量
double u = 0.1;//变异概率大于0.001
double v = 0.9;//交叉概率大于0.001
city citys[num];//citys
double dic[num][num];//distance from two citys;
int N;//real citys
int seq = 0;//当前最优序列
double answer;//最优解
int k = 1000;//迭代次数
void init() {//set N&&citys设置N和citys[num]
    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));
}
double count_energy(int* conf) {
    double temp = 0;
    for (int i = 1; i<N; ++i) {
        if (conf[i] < 0 || conf[i] >= N)
            return 0;
        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 generate(int* s) {//rand
    bool v[num];
    memset(v, false, sizeof(v));
    for (int i = 0; i<N; ++i) {
        s[i] = rand() % N;
        while (v[s[i]]) {
            s[i] = rand() % N;
        }
        v[s[i]] = true;
    }
}
void set_fitness() {
    sum_fitness = 0;
    fitness[0] = sum_energy / energy[0];
    sum_fitness += fitness[0];
    for (int i = 1; i < pop_size; ++i) {
        sum_fitness += sum_energy / energy[i];
        fitness[i] = sum_fitness;
    }
    for (int i = 0; i < pop_size; ++i) {
        fitness[i] /= sum_fitness;
    }
}
int generate_pop() {//初始化种群

    double ans = 1e9;
    int maxi = -1;
    for (int i = 0; i < pop_size; ++i) {
        generate(seq_pop[i]);
        energy[i] = count_energy(seq_pop[i]);
        sum_energy += energy[i];
        if (ans > energy[i]) {
            maxi = i;
            ans = energy[i];
        }
    }
    answer = count_energy(seq_pop[0]);
    return maxi;
}
int cho() {//选择一个
    double temp = rand() % 1000 / 1000.0;
    for (int i = 0; i < pop_size; ++i) {
        if (fitness[i] > temp)
            return i;
    }
}
int choose() {//选择
    int t_seq[pop_size][num];
    int t = 0;
    int maxi = -1;
    int ans = 1e9;
    sum_energy = 0;
    for (int i = 0; i < pop_size; ++i) {
        t = cho();
        for (int j = 0; j < N; ++j)
            t_seq[i][j] = seq_pop[t][j];
        energy[i] = count_energy(t_seq[i]);
        sum_energy += energy[i];
        if (ans > energy[i]) {
            ans = energy[i];
            maxi = i;
        }
    }
    for (int i = 0; i < pop_size; ++i) {
        for (int j = 0; j < N; ++j) {
            seq_pop[i][j] = t_seq[i][j];
        }
    }
    return maxi;
}
void solve(int seq[]) {//解决序列冲突
    bool visit[num];
    memset(visit, false, sizeof(visit));
    for (int i = 0; i < N; ++i) {
        if (seq[i] < 0 || seq[i] >= N)
            return;
        if (!visit[seq[i]]) {
            visit[seq[i]] = true;

        }
        else {
            for (int j = 0; j < N; ++j) {
                if (!visit[j]) {
                    visit[j] = true;
                    seq[i] = j;
                    break;
                }
            }
        }
    }
}
int recom() {//杂交_单点交叉
    int t_seq[2][num];

    double ans = 1e9;
    int maxi = -1;
    for (int i = 0; i < pop_size; i += 2) {
        double tt = rand() % 1000 / 1000.0;
        if (tt>v)
            continue;
        int temp = rand() % N;
        for (int j = 0; j < N; ++j) {
            if (j >= temp && j <= N) {
                t_seq[0][j] = seq_pop[i + 1][j];
                t_seq[1][j] = seq_pop[i][j];
            }
            else {
                t_seq[0][j] = seq_pop[i][j];
                t_seq[1][j] = seq_pop[i + 1][j];
            }
        }

        solve(t_seq[0]);
        solve(t_seq[1]);
        if (count_energy(t_seq[0]) < energy[i]) {
            for (int j = 0; j < N; ++j) {
                seq_pop[i][j] = t_seq[0][j];
            }
        }
        if (count_energy(t_seq[1]) < energy[i + 1]) {
            for (int j = 0; j < N; ++j) {
                seq_pop[i + 1][j] = t_seq[1][j];
            }
        }
    }
    sum_energy = 0;
    for (int i = 0; i < pop_size; ++i) {
        energy[i] = count_energy(seq_pop[i]);
        sum_energy += energy[i];
        if (ans > energy[i]) {
            ans = energy[i];
            maxi = i;
        }
    }
    set_fitness();
    return maxi;
}
int vari() {//变异
    double ans = 1e9;
    int maxi = -1;
    int temp = 0, t1 = 0, t2 = 0;
    for (int i = 0; i < pop_size; ++i) {
        temp = rand() % 1000;
        if (temp < u * 1000) {
            t1 = rand() % N;
            t2 = rand() % N;
            swap(seq_pop[i][t1], seq_pop[i][t2]);
            energy[i] = count_energy(seq_pop[i]);
        }
    }
    sum_energy = 0;
    for (int i = 0; i < pop_size; ++i) {
        sum_energy += energy[i];
        if (ans > energy[i]) {
            ans = energy[i];
            maxi = i;
        }
    }
    set_fitness();
    return maxi;
}
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() {
    int t_k = k;//迭代次数
    double ans = 1e9;
    int maxi = 0;
    int t = -2;
    double v = 1e-9;
    ans = 1e9;
    sum_fitness = 0;
    sum_energy = 0;
    memset(seq_pop, -1, sizeof(seq_pop));
    //test();//读取数据,初始化参数
    t = generate_pop();//初始化种群
    if (t >= 0 && ans > energy[t]) {
        ans = energy[t];
        maxi = t;
    }
    set_fitness();//设置适应度
    while (t_k--) {
        if (answer > ans) {
            answer = ans;
            seq = maxi;
        }
        t = choose();//选择
        if (t >= 0 && ans > energy[t]) {
            ans = energy[t];
            maxi = t;
        }
        t = recom();//杂交
        if (t >= 0 && ans > energy[t]) {
            ans = energy[t];
            maxi = t;
        }
        t = vari();//变异
        if (t >= 0 && ans > energy[t]) {
            ans = energy[t];
            maxi = t;
        }
    }
    if (answer > ans) {
        answer = ans;
        seq = maxi;
    }
}
void output() {//
    cout << "the best road is : \n";
    for (int i = 0; i < N; ++i) {
        cout << seq_pop[seq][i];
        if (i == N - 1)
            cout << endl;
        else
            cout << " -> ";
    }
    cout << "the length of the road is " << answer << endl;
}
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/79930326