在网上发现了一个 模拟退火解旅行商问题的代码,
真心觉得非常好看,
特以此作为模拟退火的模板。
#include <iostream>
#include <cstring>
#include <fstream>
#include <iterator>
#include <algorithm>
#include <limits.h>
#include <cmath>
#include <stdlib.h>
#include <cstdio>
#include <time.h>
using namespace std;
const int nCities = 100; //城市数量
const double SPEED = 0.97;//退火速度
const int INITIAL_TEMP = 1000;//初始温度
const int L = 100 * nCities;//Markov 链的长度
struct node
{
int num;
int x;
int y;
}nodes[nCities];
struct unit //一个解
{
double length;//代价,总长度
int path[nCities];//路径
bool operator < ( const struct unit &other) const
{
return length < other.length;
}
};
unit bestone = {INT_MAX, {0} };//最优解
double length_table[nCities][nCities];//邻接矩阵
void init_dis(); // 初始化
void SA_TSP(); //解决旅行商问题
void CalCulate_length(unit &p);//计算长度
void print( unit &p);//打印一个解
void getNewSolution(unit &p);// 从邻域中获去一个新解
bool Accept(unit &bestone, unit &temp, double t);//新解以Metropolis 准则接受
int main(int argc, char* argv[])
{
init_dis();
SA_TSP();
CalCulate_length(bestone);
print(bestone);
return 0;
}
//stl 中 generate 的辅助函数对象
class GenbyOne {
public:
GenbyOne (int _seed = -1): seed(_seed){}
int operator() (){return seed += 1;}
private:
int seed;
};
void SA_TSP()
{
srand(time(0));
int i = 0;
double r = SPEED;
double t = INITIAL_TEMP;
const double t_min = 0.001; //温度下限,若温度达到t_min ,则停止搜索
//生成初始解
unit temp;
generate(temp.path, temp.path + nCities, GenbyOne(0));//生成序列
random_shuffle(temp.path, temp.path + nCities);//随机生成一组解
CalCulate_length(temp);
memcpy(&bestone, &temp, sizeof(temp));
// 退火过程
while ( t > t_min )
{
for (i = 0; i < L; i++)
{
getNewSolution(temp);
if(Accept(bestone,temp, t))
{
memcpy(&bestone, &temp, sizeof(unit));
}
else
{
memcpy(&temp, &bestone, sizeof(unit));
}
}
t *= r; //退火
}
return;
}
bool Accept(unit &bestone, unit &temp, double t)
{
if (bestone.length > temp.length) //当前解更优,接受
{
return true;
}
else
{
if ((int)(exp((bestone.length- temp.length) / t) * 100) > (rand() % 101) )
{
return true; //当前解不优,以一定概率接受
}
}
return false;
}
void getNewSolution(unit &p)
{
int i = rand() % nCities;
int j = rand() % nCities;
if (i > j)
{
int t = i;
i = j;
j = t;
}
else if (i == j)
{
return;
}
//两种随机生成方法
int choose = rand() % 2;
if ( choose == 0)
{//交换i和j
int temp = p.path[i];
p.path[i] = p.path[j];
p.path[j] = temp;
}
else
{//置逆i、j之间结点
reverse(p.path + i, p.path + j);
}
CalCulate_length(p);
}
void init_dis() // 初始化
{
int i, j;
for (i = 0; i < nCities; i++)
{
nodes[i].num = i+1;
cin >> nodes[i].x >> nodes[i].y;//输入节点的坐标
}
for (i = 0; i < nCities; i++)
{
length_table[i][i] = (double)INT_MAX;
for (j = i + 1; j < nCities; j++)
{
length_table [i][j] = length_table[j][i] =sqrt(
(nodes[i].x - nodes[j].x) * (nodes[i].x - nodes[j].x) +
(nodes[i].y - nodes[j].y) * (nodes[i].y - nodes[j].y) );
}
}
}
void CalCulate_length(unit &p)
{
int j = 0;
p.length = 0;
for (j = 1; j < nCities; j++)
{
p.length += length_table[ p.path[j-1] ][ p.path[j] ];
}
p.length += length_table[ p.path[nCities - 1] ][ p.path[0] ];
}
void print( unit &p)
{
int i;
cout << "代价是:" << p.length << endl;
cout << "路径是:";
for (i = 0; i < nCities; i++)
{
cout << p.path[i] << " ";
}
cout << endl;
}
411

被折叠的 条评论
为什么被折叠?



