Dome of Tuxville [UVALive 3347] 模拟退火

题意:有n个楼,给定xy坐标和高度,有一个防护盾核心,以他为球心的半球内的都处于他的保护之下,求他的坐标,使得他需要覆盖全部楼的半径最小。

题解:

模拟退火。

 

第一个模拟退火,哈哈。

传统的模拟退火如果当前状态更有就接受,否则以一定概率接受,概率的存在保证不会跳进局部最优而出不来。

不过用概率搞貌似效果不是很好,然后就初始生成100组解,对着100组并行操作,只在更优的时候接受,这样每组解最后都会到达他所在区域的局部最优解,而全局最优解很有可能就在这些局部最优解之中,对这100组取个最优作为全局最优值。

这个方法在数据不是特别针对的情况下效果还不错,特别怕那种锯齿形的有很多局部最优解的数据。

 

#include<stdio.h>

#include<memory.h>

#include<iostream>

#include<algorithm>

#include <stdlib.h>

#include <time.h>

#include<cmath>

using namespace std;

#define TN 180

int n;

struct pt

{

double x,y,h;

};

struct status

{

pt p;

double e,r;

};

pt a[105];

double calc_r(pt a,pt b)

{

   return sqrt(  (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y) +a.h*a.h );

}

double max_r(pt x)

{

int i;

double ans=0,t;

for(i=1;i<=n;i++)

if ((t=calc_r(a[i],x))>ans)

ans=t;

return ans;

}

 

status s0[2000],s[2000];

double t0;

double P(double se,double ee)

{

return exp(-(ee-se)/ee);

}

double fmax(double x,double y)

{

if (x>y) return x;

else return y;

}

int main()

{

int i,j,k,u;

double minx,miny,maxx,maxy;

srand(time(NULL));

while(cin>>n)

{

if (n==0) break;

minx=10000000;maxx=-100000000;miny=100000000;maxy=-10000000;

for(i=1;i<=n;i++)

{

cin>>a[i].x>>a[i].y>>a[i].h;

   if (a[i].x<minx) minx=a[i].x;

if (a[i].x>maxx) maxx=a[i].x;

if (a[i].y<miny) miny=a[i].y;

if (a[i].y>maxy) maxy=a[i].y;

}

for(i=0;i<=TN;i++)

{

    s0[i].p.x=minx+i*(maxx-minx)/TN;

s0[i].p.y=miny+i*(maxy-miny)/TN;

s0[i].e=max_r(s0[i].p);

}

        for(double len=fmax(maxx-minx,maxy-miny);len>1e-7;len*=0.9)

for(u=0;u<=TN;u++)

{

double ang=(rand()%32768)*1.0/32768*6.283;

s[u].p.x=s0[u].p.x+sin(ang)*len;

s[u].p.y=s0[u].p.y+cos(ang)*len;

s[u].e=max_r(s[u].p);

if (s[u].e<s0[u].e) s0[u]=s[u];

}

int ans;

double anse;

anse=10000000;

for(i=0;i<=TN;i++)

if (anse>s0[i].e)

{

                anse=s0[i].e;

ans=i;

}

 

printf("%.3lf %.3lf/n",s0[ans].p.x,s0[ans].p.y);

}

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值