模拟退火SA刷题记录

洛谷P1337 [JSOI2004]平衡点 / 吊打XXX

  • 基本上是照着别人的代码写的,模拟退火为什么一定能找到答案呢。。。迷惑,,有时间搜一搜证明啥的
  • sa步骤:这个是要确定一个(xi,yi)使得函数()值最小,所以先选一个开始的点(这里选的是所有桌子上的点的均值),然后(rand()*2-RAND_MAX)*T就是deltax,deltay,然后再算出移动了这个delta后的函数值,该函数值如果是一个更小的值,则接受,否则如果( exp(-delta/T)*RAND_MAX>rand() )才接受,注意这里的delta是函数值的差值,这个exp(-delta/T)是一个在0,1之间的数。
  • 产生移动距离:(rand()*2-RAND_MAX)*T  (这样正负都有)
  • 以一定的概率接受移动:exp(-delta/T)*RAND_MAX>rand()
  • 步骤:找到需要最优化的函数,找到移动方案,徐徐降温直到温度达到exp=1e-15退出,输出答案
  • 代码:
     1 #include <bits/stdc++.h>
     2 #define nmax 1010
     3 
     4 using namespace std;
     5 int n;
     6 double x[nmax],y[nmax],w[nmax];
     7 double ansx,ansy;
     8 const double eps=1e-15;
     9 
    10 int cnt=0;
    11 
    12 double f(double nx,double ny){
    13     double tot=0,tmp;
    14     for (int i=0; i<n; i++) {
    15         tmp=sqrt( (nx-x[i])*(nx-x[i])+(ny-y[i])*(ny-y[i]) );
    16         tot+=tmp*w[i];
    17     }
    18     return tot;
    19 }
    20 
    21 void sa(){
    22     double t=200.0;
    23     while(t>eps){
    24         double nowx=ansx+(rand()*2-RAND_MAX)*t,nowy=ansy+(rand()*2-RAND_MAX)*t;  
    25         double delta=f(nowx,nowy)-f(ansx,ansy);
    26         if( delta<0 || ( exp(-delta/t)*RAND_MAX>rand() ) ) { ansx=nowx; ansy=nowy;  }
    27         t*=0.998;
    28     }
    29 }
    30 
    31 int main(){
    32     srand((int)time(NULL));
    33     cin>>n;
    34     for (int i=0; i<n; i++) {
    35         scanf("%lf%lf%lf",&x[i],&y[i],&w[i]);
    36         ansx+=x[i];
    37         ansy+=y[i];
    38     }
    39     ansx/=(double)n;
    40     ansy/=(double)n;
    41     sa();
    42     printf("%.3lf %.3lf\n",ansx,ansy);
    43     return 0;
    44 }
    😔

20182019-acmicpc-asia-nanjing-regional-contest

D Country Meow

  • 最小球覆盖。。。没看网上的做法,写了个普通的模拟退火,反正这道题是过了。。好像这题数据很水的
  • 看出容易用模拟退火的题的一个特点:答案的精度要求大概在1e-3
  • 代码:
     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstdlib>
     5 #include <ctime>
     6 #include <cmath>
     7 #define nmax 110
     8 
     9 using namespace std;
    10 int n;
    11 double x[nmax],y[nmax],z[nmax];
    12 const double eps = 1e-15;
    13 double ansx,ansy,ansz;
    14 
    15 double f(double nx,double ny,double nz){
    16     double maxa=0;
    17     for (int i=0; i<n; i++) {
    18         double tx=nx-x[i],ty=ny-y[i],tz=nz-z[i];
    19         maxa=max(maxa,sqrt(tx*tx+ty*ty+tz*tz));
    20     }
    21     return maxa;
    22 }
    23 
    24 void sa(){
    25     double t=20000.0;
    26     while(t>eps){
    27         double tx=ansx+(rand()*2-RAND_MAX)*t,ty=ansy+(rand()*2-RAND_MAX)*t,tz=ansz+(rand()*2-RAND_MAX)*t;
    28         double delta=f(tx,ty,tz)-f(ansx,ansy,ansz);
    29         if(delta<=0|| ( exp(-delta/t)*RAND_MAX>rand() ) ) ansx=tx,ansy=ty,ansz=tz;
    30         t*=0.999;
    31     }
    32 }
    33 
    34 int main(){
    35     srand((int)time(NULL));
    36     cin>>n;
    37     double minx=20000000,miny=20000000,minz=20000000,maxx=-20000000,maxy=-20000000,maxz=-20000000;
    38     for (int i=0; i<n; i++) {
    39         scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);
    40         minx=min(minx,x[i]);
    41         miny=min(miny,y[i]);
    42         minz=min(minz,z[i]);
    43         maxx=max(maxx,x[i]);
    44         maxy=max(maxy,y[i]);
    45         maxz=max(maxz,z[i]);
    46     }
    47     ansx=minx+(maxx-minx)/2;
    48     ansy=miny+(maxy-miny)/2;
    49     ansz=minz+(maxz-minz)/2;
    50     sa();
    51     sa();
    52     sa();
    53     printf("%lf",f(ansx,ansy,ansz));
    54     return 0;
    55 }
    😟

     

posted @ 2019-10-04 12:13  连昵称都不能重复  阅读(167)  评论(2编辑  收藏  举报