模拟退火求解TSP问题<2变换法产生路径>

模拟退火求解TSP问题

/*
 * @file2                              SA.cpp
 * @brief                             SA解TSP
 * @author/Univ.                 taoxiaoxiao/XMU
 * @date                              11-2-2014
*/

#include <iostream>
#include <fstream>
#include <random>
using namespace std;

#define max 51                                                             //最大的输入规格
int a[max][max];                                                                //距离矩阵
int curPath[max], newPath[max], bestPath[max];          //当前解、新解、最优解
int length, bestLength = 0;                                             //解的结果、最优解的结果
int n;                                                                              //输入的节点数
int Lk= 2000;                                                                   //Mapkob链长
double t = 100.0, alpha = 0.9;                                          //温度、衰减速度

double rand1()
{
        //产生0-1间随机数

    static default_random_engine e;                                         //引擎
    static uniform_real_distribution<double> u(0, 1);                   //  分布

    return u(e);
}

int rand2(int n)
{
    static default_random_engine e;                                         //引擎
    static uniform_int_distribution<int> u(1, n);                   //  分布
    return u(e);
}

inline void swap(int &a, int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

int getLength(int *p) 
{
    int len = 0;
    for (int i = 1; i <= n - 1; ++i) 
    {
        len += a[p[i]][p[i + 1]];
    }
    len += a[p[n]][p[1]];
    
    return len;
}

/*2变换法产生新路径*/
int getNewPath()
{
    //获得新路径,并求出新长度
    int k, m;
    int newLen = 0;

    /* 2分交换 */
    while (1)
    {
        k = rand2(n);
        m = rand2(n);
        if (k != m)
            break;
    }
    /* 新路径 */
    swap(newPath[k], newPath[m]);
    newLen = getLength(newPath);

    return newLen;
}

void sa() 
{
    int i, count;
    int newLength, delta;
    int s = 0;
    int bChange = 0;

    /*初始化操作*/
    for (i = 1; i<= n; i++) 
    {
        bestPath[i]=newPath[i]=curPath[i] = i;
    }
    length = getLength(curPath);
    bestLength = length;

    /*按Metropolis接受准则进行迭代*/
    while (1) 
    {
        count = 0;
        //对每个温度tk产生Lk个解 Lk个解构成一个mapkob链
        while (1) 
        {
            newLength = getNewPath();
            delta = newLength - length;
            if (delta <= 0 || (delta>0 && exp(-delta / t)>rand1())) 
            {       
                //是否接受新解
                bChange = 1;
                for (i = 1; i <= n; i++) 
                {
                    curPath[i] = newPath[i];
                }
                length = newLength;
                if (length < bestLength) 
                {
                    bestLength = length;
                    for (i = 1; i <= n; i++) 
                    {
                        bestPath[i] = curPath[i];
                    }
                }
            }
            if (++count >= Lk) 
                break;
        }//1-while

        t = alpha * t;          //降温
        if (1==bChange) 
        {
            s = 0;
            bChange = 0;
        }
        else 
        {
            s++;
        }
        if (s == 2 || t <=1e-6)
        {           
            //停止准则
            //温度接近零或者有两次结果没变化时
            break;
        }
    }//2-while
}

int main() 
{
    ifstream infile("file2.txt");

    int i, j;
    if (infile.is_open())
        cout << "open file successful." << endl;
    else
    {
        cout << "open file error." << endl;
        return 0;
    }
    while (!infile.eof())
    {
        infile >> n;
        for (i = 1; i <= n; ++i)
        {
            for (j =1; j <= n; ++j)
                infile >> a[i][j];
        }
    }
    infile.close();

    sa();
    for (i = 1; i <= n; ++i)
        cout << bestPath[i] << "->";
    cout << bestPath[1] << endl;
    cout << bestLength << endl;
    system("pause");

    return 0;
}


file2.txt

 

运行结果


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值