模拟退火 get !
模拟退火大法好!
简单介绍一下模拟退火:(摘自大佬的讲义)
模拟退火算法来源于固体退火原理,
将固体加温至充分高,再让其徐徐冷却。
加温时,固体内部粒子随温升变为无序状,内能增大,
而徐徐冷却时粒子渐趋有序,
在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。
根据Metropolis准则,粒子在温度T时趋于平衡的概率为 e-ΔE/(kT)
其中E为温度T时的内能,ΔE为其改变量,k为Boltzmann常数。
模拟退火实际上就模拟了这个过程。
模拟退火适用于解决 TSP 问题, 其特点在于有一定几率接受一个较差解,以减小陷入局部最优解的概率。
入门:
codevs 1344
翻到隔壁 codevs 去做了道模板题,利用结构体存连接顺序,不断的找较优解
int n;
double tot=0x3f3f3f3f;
double x[30],y[30];
double map[30][30];
struct Path{
int path[30];
Path(){
for(int i=1;i<=n;i++) path[i] = i;
}
Path(const Path &p){
memcpy(path,p.path,sizeof(path) );
swap(path[rand()%n+1],path[rand()%n+1]);
}
double dist()
{
double len=0;
for(int i=1;i<n;i++)
len += map[path[i]][path[i+1]];
return len;
}
};
bool accept(double delta, double temp)
{
if(delta <= 0) return 1;
return rand()<=exp((-delta)/temp)*RAND_MAX;
}
double solve()
{
Path p;
const double Tem = 100;
const double del = 0.99;
double ans = 0x3f3f3f3f;
double tempre = Tem;
while(tempre >= 0.01)
{
Path p2(p);
if(accept(p2.dist()-p.dist(),tempre))
p = p2;
tempre *= del;
}
return p.dist();
}
int main(void)
{
srand(time(NULL));
cin >> n;
for(int i=1;i<=n;i++)
cin >> x[i] >> y[i];
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
{
map[i][j] = sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
map[j][i] = map[i][j];
}
for(int i=1;i<=355;i++)
tot = min(tot,solve());
printf("%.2lf",tot);
return 0;
}