C++:蚁群算法解决TSP(C++多线程版)

本文介绍了使用C++编程实现蚁群算法解决旅行商问题(TSP),并应用在att48数据集上,采用多线程优化计算效率。内容包括对TSP问题的定义、蚁群算法的原理以及具体的C++代码实现。
摘要由CSDN通过智能技术生成

TSP问题:旅行商问题,最短回路。

这里采用att48数据,邻接矩阵全部取整数,原数据放在文后。

解决代码如下:

//#define TEST_INPUT
//#define TEST_T
//#define TEST_ANT
//#define TEST_VALUE

#include<cstdio>
#include<cstring>
#include<thread>
#include<vector>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#include<cmath>

using namespace std;

#define eps 0.000001     //浮点数精度
#define maxn 50         //最大支持50座城市


mutex lock;             //锁


int city = 48;          //城市数量
int num = 1000;       //蚂蚁数量
int iteration = 100;          //迭代次数
double alpha = 1;           //信息素比重
double beta = 2;            //开销比重
double evaporation = 0.997;   //蒸发速率
double Q = 100;             //信息素增加量


int G[maxn+2][maxn+2];      //开销,城市编号从1开始
double D[maxn+2][maxn+2];   //开销倒数
double T[maxn+2][maxn+2];   //信息素


int ans = 0x7fffffff;   //最优解
vector<int> res;        //最优路径


//print the result
void output()
{
    printf("the shortest circle: ");
    for(vector<int>::iterator p=res.begin();p!=res.end();p++)
    {
        printf("%d%s",*p,p==res.end()-1?"\n":" ");
    }
    printf("the shortest circle cost: %d\n",ans);
}

//output to the file
void output_file()
{
    FILE* f = fopen("output.txt","w");
    fprintf(f,"%d\n",ans);
    for(vector<int>::iterator p=res.begin();p!=res.end();p++)
    {
        fprintf(f,"%d%s",*p,p==res.end()-1?"\n":" ");
    }
    fclose(f);
}

//print the and T
void print_T()
{
    printf("\nT:\n");
    for(int i=1;i<city+1;i++)
    {
        for(int j=1;j<city+1;j++)
        {
            printf("%f%s",T[i][j],j==city?"\n":" ");
        }
    }
}

//初始化
void init()
{
    memset(G,0,sizeof(G));
    memset(D,0,sizeof(D));
    memset(T,0,sizeof(T));
    res.clear();
    FILE* f = NULL;
    f = fopen("att48_d.txt","r");


#ifdef TEST_INPUT
    fclose(f);
    f = fopen("input.txt","r");
    city = 9;
    num = 100;
    iteration = 100;
#endif

    for(int i=1;i<city+1;i++)
    {
        for(int j=1;j<city+1;j++)
        {
            fscanf(f,"%d",&G[i][j]);
        }
    }
    fclose(f);

    for(int i=1;i<city+1;i++)
    {
        for(int j=1;j<city+1;j++)
        {
            if(i==j) continue;
            D[i][j] = 1.0/G[i][j];       //初始D为开销的倒数
            T[i][j] = 1.0;              //初始信息素T为1
        }
    }
}


//[x,y]随机整数
int get_random_int(int x,int y)
{
    return (int)rand()%(y-x+1)+x;
}


//[x,y]随机小数
double get_random_float(int x,int y)
{
    return (double)rand()/(RAND_MAX)*(y-x) + x;
}


//蚂蚁
void ant(int id)
{
    vector<int> A;                                      //已经访问过
    vector<int> B;                                      //需要访问
    int s = get_random_int(1,city);
    A.push_back(s);                                     //随机选择起始城市
    for(int i=1;i<city+1;i++) if(i!=s) B.push_back(i);  //待访问城市列表

    while(!B.empty())
    {
        double sum = 0;
        double best_v = 0;
        vector<int>::iterator best_city;

        lock.lock();

        //获取所有去向的评估值之和
        for(vector<int>::iterator p=B.begin();p!=B.end();p++) sum+=(pow(T[s][*p],alpha)*pow(D[s][*p],beta));

        //评估每一个需要被访问的城市
        for(vector<int>::iterator p=B.begin();p!=B.end();p++) {
            //当前城市
            int c = *p;

            //当前城市评估值
            double v = pow(T[s][c], alpha) * pow(D[s][c], beta) / sum;

            if (v > best_v) {
                best_city = p;
                best_v = v;

            }

            //评估值越大的城市越有几率成为下一个访问城市
            double r = get_random_float(0, 1);

#ifdef TEST_VALUE
            printf("ant:%d    last:%d    now:%d   r:%f      v:%f\n", id, *(A.end() - 1), c, r, v);
#endif
            if (r <= v + eps) {                         //这个比较值需要修改
                A.push_back(c);
                B.erase(p);
                break;
            }
        }

        lock.unlock();
    }

    //蚂蚁走完了所有城市
    int sum = 0;

    //获取路径总花费
    for(vector<int>::iterator p=A.begin()+1;p!=A.end();p++)
    {
        sum+=G[*(p-1)][*p];

#ifdef TEST_ANT
        printf("ant:%d   sum:%d   s:%d t:%d\n",id,sum,now,*p);
#endif

    }
    sum+=G[*(A.end()-1)][*(A.begin())];

#ifdef TEST_ANT
    printf("ant:%d   sum:%d   s:%d t:%d\n",id,sum,*(A.end()-1),*(A.begin()));
#endif

    //更新信息素
    lock.lock();
    for(vector<int>::iterator p=A.begin()+1;p!=A.end();p++)
    {
        T[*(p-1)][*p]+=(Q/sum);
    }
    T[*(A.end()-1)][*(A.begin())]+=(Q/sum);

    //如果当前最佳路径为空,则用当前路径初始化最佳路径
    if(res.empty())
    {
        res = A;
        ans = sum;
    }
    else if(sum < ans)
    {
        res = A;
        ans = sum;
    }

#ifdef TEST_T
    printf("\nant:%d\n",id);
    print_T();
#endif

    lock.unlock();
}


int main()
{
    srand((unsigned)time(0));
    init();
    for(int k=0;k<iteration;k++)
    {
#ifdef TEST_T
        printf("iteration:%d\n",k);
#endif

        vector<thread> t;
        for(int i=0;i<num;i++) t.push_back(thread(ant,i));
        for(int i=0;i<num;i++) t[i].join();

        for(int i=1;i<city+1;i++)
        {
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值