模拟退火 [JSOI2004]平衡点 / 吊打XXX

一曲冷凌霜 提交于 2019-11-30 06:31:51

 

本人水平有限,题解不到为处,请多多谅解

 

本蒟蒻谢谢大家观看

 

 

题目传送门

 

大致的模拟退火讲解我这里不再赘述,如有疑问请看这里

传送门连接

 

code:

#include <bits/stdc++.h>
#define down 0.996//徐徐降温 
using namespace std;
int n;
struct node{
int x;
int y;
int w;
}object[2005];//存下物体的坐标 
double ansx,ansy,answ;//最终答案 
double energy(double x,double y)//根据物理学知识,能量总和越小越稳定 
{
   double r=0,dx,dy;
   for (int a=1;a<=n;a++)
   {
      dx=x-object[a].x;
      dy=y-object[a].y;
      r+=sqrt(dx*dx+dy*dy)*object[a].w;
   }
      return r;
}
void sa()//模拟退火 
{
   double t=3000;//温度要足够高 
   while (t>1e-15)//略大于0 
   {
       //生成[-T*RAND_MAX,T*RAND_MAX)的随机变动范围(rand():[0,RAND_MAX))
       //rand()一个随机数,RAND_MAX随机范围内最大值
      double ex=ansx+(rand()*2-RAND_MAX)*t;//随机产生新的答案 
      double ey=ansy+(rand()*2-RAND_MAX)*t;
      double ew=energy(ex,ey);
      double de=ew-answ;
      if (de<0)//如果此答案更优,就接受 
      {
         ansx=ex;
         ansy=ey;
         answ=ew;
      }
      else if(exp(-de/t)*RAND_MAX>rand())
      //以概率exp(-Δt′/T)接受S′作为新的当前解S。
      //否则根据多项式概率接受 
      {
         ansx=ex;
         ansy=ey;
      }
      t*=down;
   }
}
void solve()//多跑几遍退火,增加得到最优解的概率 
{
   sa();
   sa();
   sa();
   sa();
}
int main() 
{
    cin>>n;
    for (int a=1;a<=n;a++)
    {
           scanf("%d%d%d",&object[a].x,&object[a].y,&object[a].w);
           ansx+=object[a].x;
           ansy+=object[a].y;
    }
        ansx/=n;//以平均数作为初始答案 
        ansy/=n;
        answ=energy(ansx,ansy);
        solve();
        printf("%.3lf %.3lf\n",ansx,ansy);//华丽的输出 
            return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!