模拟退火

模拟退火

概述:求解最优化问题,example:TSP,函数max/min

一、理论:

算法认识:基于爬山算法(每次朝着当前上升最快的方向爬,但是初始化不同可能会得到不同的局部最优值,模拟退火可能跳出局部最优值)

流程:初始高温-->温度降低-->终止在低温

本质:贪心+随机化

二、算法描述:

\[\begin{cases} \text{if f[x+1] > f[x] 移动后更优,那么总是移动} \\ \text{if f[x+1]< f[x]移动后更差,那么以一定的概率移动,并且这个概率随时移动} \end{cases} \]

       $P(dE)=exp(\frac{dE}{kT})$

dE<0,说明:温度越高出出现的能量差为dE的降温概率越大,温度越低

伪CODE:

/*
F(h[x]) 为估价函数
h[x] 为当前的状态
delta 控制降温的快慢
T 系统的温度,初始温度比较高
T_min 温度的下限,若温度达到T_min,停止搜索
*/
 while(T>T_min){
  y=x+rand()*t;
  dE=F(h[y])-F(h[x]);
  if(dE>=0)
     h[y]=h[x];//转移更优,那么转移
  else {
     //dE的越大,那么次语句的条件成立概率越大,T越小exp(dE/T)越小
   if(exp(dE/T)>random(0,1)){//exp(dE/T)表示以e(自然常数)为底的(dE/T)次方
        h[y]=h[x];
   }
  }
  T*=delta//delta 一般取0.98/0.99
 }

三·、经典例题:

1.[JSOI2004]吊打XXX

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<ctime>
#include<cstdlib>
using namespace std;
const int MAXX=1010;
int x[MAXX],y[MAXX],w[MAXX];
double ansx,ansy;
int sumx,sumy,n;
inline double cal(double x0,double y0){
 double ans=0;
 for(int i=1;i<=n;++i){
  double xx=(double)x[i]-x0;
  double yy=(double)y[i]-y0;
  ans+=(double)sqrt(xx*xx+yy*yy)*w[i];
 }
 return ans;
}
inline void SA(){
 ansx=(double)sumx/n;
    ansy=(double)sumy/n;
 double t=1926;
 double t_min=1e-14;
 double delta=0.98;
 while(t>t_min){
  double randx=ansx+(rand()%20000-10000)*t;
  double randy=ansy+(rand()%20000-10000)*t;
  double dE=cal(randx,randy)-cal(ansx,ansy);
  if(dE<=0){
   ansx=randx;
   ansy=randy;
  }else {
   if(exp(-dE/t)*RAND_MAX>rand()){
    ansx=randx;
    ansy=randy;
   }
  }
  t*=delta;
 }
}
int main(){
 srand(time(NULL));
 scanf("%d",&n);
 for(int i=1;i<=n;++i){
  scanf("%d%d%d",&x[i],&y[i],&w[i]);
  sumx+=x[i];
  sumy+=y[i];
 }
    SA();SA();SA();
    printf("%.3lf %.3lf",ansx,ansy);
    return 0;
}
/*
INPUT:
3
0 0 1
0 2 1
1 1 1
OUTPUT:
0.577 1.000
*/
posted @ 2018-08-26 19:47  ART_coder  阅读(238)  评论(0编辑  收藏  举报