遗传算法解决旅行商问题(TSP)(实验课)

问题描述

在旅行商问题中,给定一组城市及每座城市与其他城市之间的旅行成本,目标是找出一条经过所有城市的路径,要求该路径只经过每座城市一次并且旅行总成本最低。从任意一座城市出发,经过每一座城市之后,再回到出发城市结束旅行。
距离矩阵
课上给的距离矩阵,可能是疏忽9到3和3到9的距离不一致,但这不妨碍程序设计

代码部分

#include<iostream>
#include<algorithm>
#include<ctime>

#define num_c 10//城市个数
#define Max_t 100//种群数量
#define rate 0.6//选择率
#define generation 1000//迭代次数
#define v_rate 10//变异率百分比
using namespace std;
//城市距离矩阵
int distance_t[10][10] = {
    { 0,118,1272,2567,1653,2097,1425,1177,3947,1574 },
    { 118,0,1253,2511,1633,2077,1369,1157,3961,1518 },
    { 1272,1253,0,1462,380,1490,821,856,3660,385 },
    { 2567,2511,1462,0,922,2335,1562,2165,3995,933 },
    { 1653,1633,380,922,0,1700,1041,1135,3870,456 },
    { 2097,2077,1490,2335,1700,0,2311,920,2170,1920 },
    { 1425,1369,821,1562,1041,2311,0,1420,4290,626 },
    { 1177,1157,856,2165,1135,920,1420,0,2870,1290 },
    { 3947,3961,3660,3995,3870,2170,4290,2870,0,4090 },
    { 1574,1518,385,993,456,1920,626,1290,4090,0 } };

//种群个体
class solution_t
{
public:
    int path[num_c];//记录城市路径
    int cost;//总路径长度,也就是适应度
             //重载小于号,便于排序
    bool operator <(const solution_t &a)const
    {
        return cost < a.cost;
    };
    //计算当前的cost
    void computeCost()
    {
        int sum = 0;
        for (int i = 1; i < num_c; i++)
            sum += distance_t[path[i - 1]][path[i]];
        sum += distance_t[path[0]][path[num_c - 1]];
        cost = sum;
    }
    //对个体进行变异,也就是随机交换两个位置的元素
    void variation()
    {
        int a, b;
        a = rand() % num_c;
        b = rand() % num_c;
        swap(path[a], path[b]);
    }
};

solution_t population[Max_t];//种群
solution_t nextpo[Max_t];//存储子代的临时数组

//初始化种群,先将个体顺序初始化,就是赋值为0123456789
//然后随机扰动5次,随机交换两个位置的元素
void init(solution_t(&population)[Max_t])
{
    srand((unsigned)time(0));
    for (int i = 0; i < Max_t; i++)
    {
        for (int j = 0; j < num_c; j++)
        {
            population[i].path[j] = j;
        }
        for (int j = 0; j < num_c / 2; j++)
        {
            int a, b;
            a = rand() % num_c;
            b = rand() % num_c;
            swap(population[i].path[a], population[i].path[b]);
        }
    }
}

//选择一定比例适应度高的个体,并从保留下来的个体中随机选择个体,填充剩余位置
void select(solution_t(&population)[Max_t])
{
    sort(population, population + Max_t);
    int s = (int)(Max_t*rate);
    for (int i = s + 1; i < Max_t; i++)
    {
        int num = rand() % s;
        population[i] = population[num];
    }
}

//交叉的过程,a b是父代 a1 b1是子代
void exchange(solution_t a, solution_t b, solution_t &a1, solution_t &b1)
{
    //随机选取一段基因
    int left = rand() % num_c;
    int right = (rand() % (num_c - left)) + left;

    //交叉互换
    for (int i = left; i <= right; i++)
        swap(a.path[i], b.path[i]);
    bool flag;
    flag = true;//判断是否有冲突

                //以下是消除冲突的过程
    while (flag)
    {
        int num = 0;
        for (int i = left; i <= right; i++)
        {
            for (int j = 0; j < num_c; j++)
            {
                if (j >= left&&j <= right)
                    continue;
                if (a.path[i] == a.path[j])
                {
                    a.path[j] = b.path[i];
                    num++;
                }
            }
        }
        if (num == 0)
            flag = false;
    }
    flag = true;
    while (flag)
    {
        int num = 0;
        for (int i = left; i <= right; i++)
        {
            for (int j = 0; j < num_c; j++)
            {
                if (j >= left&&j <= right)
                    continue;
                if (b.path[i] == b.path[j])
                {
                    b.path[j] = a.path[i];
                    num++;
                }
            }
        }
        if (num == 0)
            flag = false;
    }
    //输出a1 b1 不用a b是为了不改变父代
    for (int i = 0; i < num_c; i++)
    {
        a1.path[i] = a.path[i];
        b1.path[i] = b.path[i];
    }
}
int main()
{
    init(population);
    srand((unsigned)time(0));

    for (int j = 0; j < Max_t; j++)
        population[j].computeCost();
    for (int i = 0; i < generation; i++)
    {

        select(population);

        //交叉互换
        int counter = 0;
        for (int j = 0; j < Max_t / 2; j++)
        {
            int a = rand() % num_c;
            int b = rand() % num_c;
            exchange(population[a], population[b], nextpo[counter], nextpo[counter + 1]);
            counter = counter + 2;
        }

        //随机变异
        for (int j = 0; j < Max_t; j++)
        {
            int r = rand() % 100;
            if (r <= v_rate)
                nextpo[j].variation();
        }

        //计算适应度
        for (int j = 0; j < Max_t; j++)
            nextpo[j].computeCost();

        //覆盖父代
        for (int j = 0; j < Max_t; j++)
            population[j] = nextpo[j];

        //输出
        cout << "generation: " << i << endl;
        for (int k = 0; k < Max_t; k++)
        {
            cout << "unit " << k << ": ";
            for (int j = 0; j < num_c; j++)
            {
                cout << population[k].path[j] << "   ";
            }
            cout << "  cost:" << population[k].cost << endl;
        }
    }
    return 0;
}

结果输出

遗传算法得到的不一定是最优解,而是近似最优解,所以可以每次收敛到的数值都不一样。
结果

猜你喜欢

转载自blog.csdn.net/wayway0554/article/details/80285711