模拟退火求解旅行商问题

不用说,一看标题就知道,又是人工智能课的实验了……

首先不妨转载一下网上看来的算法描述:

模拟退火算法可分为解空间、目标函数和初始解三部分,其基本思想是: 
(1)初始化:初始温度 $T$(充分大),初始解状态 $s$(是算法迭代的起点),每个 $T$ 值的迭代次数为 $L$; 
(2)对 $k = 1, ……, L$ 做第(3)至第(6)步; 
(3)产生新解 $s′$; 
(4)计算增量 $Delta c=cost(s′)-cost(s)$,其中 $cost(s)$ 为评价函数; 
(5)若 $Delta c le 0$ 则接受 $s′$ 作为新的当前解,否则以概率 $exp(-Delta c/T)$ 接受 $s′$ 作为新的当前解; 
(6)如果满足终止条件则输出当前解作为最优解,结束程序。终止条件通常取为连续若干个新解都没有被接受时终止算法。 
(7)$T$ 逐渐减少,且 $T$ 趋于 $0$,然后转第 $2$ 步运算。

转载的流程图:

测试用例(城市编号、横坐标、纵坐标):

1 20833.3333 17100.0000
2 20900.0000 17066.6667
3 21300.0000 13016.6667
4 21600.0000 14150.0000
5 21600.0000 14966.6667
6 21600.0000 16500.0000
7 22183.3333 13133.3333
8 22583.3333 14300.0000
9 22683.3333 12716.6667
10 23616.6667 15866.6667
11 23700.0000 15933.3333
12 23883.3333 14533.3333
13 24166.6667 13250.0000
14 25149.1667 12365.8333
15 26133.3333 14500.0000
16 26150.0000 10550.0000
17 26283.3333 12766.6667
18 26433.3333 13433.3333
19 26550.0000 13850.0000
20 26733.3333 11683.3333
21 27026.1111 13051.9444
22 27096.1111 13415.8333
23 27153.6111 13203.3333
24 27166.6667 9833.3333
25 27233.3333 10450.0000
26 27233.3333 11783.3333
27 27266.6667 10383.3333
28 27433.3333 12400.0000
29 27462.5000 12992.2222

注:任意两城市间距离为欧氏距离。

数据来源:http://www.math.uwaterloo.ca/tsp/world/wi29.tsp

最优路径长度:27603

代码:

#include<bits/stdc++.h>
#define pb(x) push_back(x)
using namespace std;
const double r=0.95; //退火系数
const double Tmin=1e-8; //终止温度
const int maxStep=1000;
const int N=105;

struct City{
    int id;
    double x,y;
    City(){}
    City(int _id,double _x,double _y) {
        id=_id, x=_x, y=_y;
    }
};
vector<City> cities; //城市信息存储
int pos[N];

vector<int> now,nxt; //路径存储

inline double Dist(const City& a,const City& b)
{
    return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));
}
double Length(const vector<int>& p)
{
    double res=0.0;
    for(int i=0;i<p.size();i++)
    {
        int x=pos[p[i]], y=pos[p[(i+1)%p.size()]];
        res+=Dist(cities[x],cities[y]);
    }
    return res;
}

int main()
{
    srand(time(nullptr));

    int id; double x,y;
    while(cin>>id>>x>>y)
        cities.pb(City(id,x,y)), pos[id]=cities.size()-1;

    for(auto x:cities) now.pb(x.id);
    random_shuffle(now.begin(),now.end());

    cout<<"初始解路径:"<<endl;
    for(auto x:now) cout<<x<<' '; cout<<endl;

    double T=50000.0;
    while(T>Tmin)
    {
        for(int step=1;step<=maxStep;step++)
        {
            nxt=now;
            int u=0, v=0;
            while(u==v) u=rand()%nxt.size(), v=rand()%nxt.size();
            swap(nxt[u],nxt[v]);

            double L1=Length(now), L2=Length(nxt);
            if(L2-L1<0) now=nxt;
            else
            {
                double rnd=(rand()%101)*1.0/100.0;
                if(rnd<exp((L1-L2)/T)) now=nxt;
            }
        }
        T*=r;
    }

    cout<<"最终解路径:"<<endl;
    for(auto x:now) cout<<x<<' '; cout<<endl;
    cout<<"路径总长度:"<<endl;
    cout<<Length(now)<<endl;
}

结果:

由于随机数种子设定缘故,每次运行结果都不一样,给出某一次运行的结果。

原文地址:https://www.cnblogs.com/dilthey/p/10646260.html