hdu 1109 Run Away 模拟退火

为什么我的眼中常含泪水。因为我还有一个算法不会……为了少流点泪,还是多码点题……

今天学了模拟退火算法,听起来很高大上,实现起来代码很少。先贴一个模拟退火的物理解释(来源于百度百科)

模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,固体内部粒子温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在常温时达到基态,内能减为最小。

额,应该看不懂吧……在博客上看到了一个很有意思的解释:

想象把一群喝醉的兔子随机放到山群中,兔子要往山顶走,一开始兔子摇摇晃晃的,可能往上走,可能往下走,后来兔子们清醒了,坚定的往山顶走。这样,在很高的概率下,总有一只兔子能走到最高的山顶。

这样理解起来就很容易了吧。概括来说就是,一开始兔子的脚步很大,也容易往下走,随着时间的推移,兔子的脚步越来越小,逐渐的不接受往下走的更新,这就是退火的原理。

这和爬山算法的区别是什么呢?就是以(随时间推移而减小的)概率接受往下走的状态更新。

hdu1109是一道基本的退火题,题目如下:

Run Away

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1619    Accepted Submission(s): 669


Problem Description
One of the traps we will encounter in the Pyramid is located in the Large Room. A lot of small holes are drilled into the floor. They look completely harmless at the first sight. But when activated, they start to throw out very hot java, uh ... pardon, lava. Unfortunately, all known paths to the Center Room (where the Sarcophagus is) contain a trigger that activates the trap. The ACM were not able to avoid that. But they have carefully monitored the positions of all the holes. So it is important to find the place in the Large Room that has the maximal distance from all the holes. This place is the safest in the entire room and the archaeologist has to hide there.
 

Input
The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing three integers X, Y, M separated by space. The numbers satisfy conditions: 1 <= X,Y <=10000, 1 <= M <= 1000. The numbers X and Yindicate the dimensions of the Large Room which has a rectangular shape. The number M stands for the number of holes. Then exactly M lines follow, each containing two integer numbers Ui and Vi (0 <= Ui <= X, 0 <= Vi <= Y) indicating the coordinates of one hole. There may be several holes at the same position.
 

Output
Print exactly one line for each test case. The line should contain the sentence "The safest point is (P, Q)." where P and Qare the coordinates of the point in the room that has the maximum distance from the nearest hole, rounded to the nearest number with exactly one digit after the decimal point (0.05 rounds up to 0.1). 
 

Sample Input
 
 
3 1000 50 1 10 10 100 100 4 10 10 10 90 90 10 90 90 3000 3000 4 1200 85 63 2500 2700 2650 2990 100
 

Sample Output
 
 
The safest point is (1000.0, 50.0). The safest point is (50.0, 50.0). The safest point is (1433.0, 1669.8).
 

题意分析:求全局最优点,使得这个最优点到所有点的最小值(欧式距离)最大

直接贴代码啦:



#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<stdlib.h>
#include<math.h>
#include<time.h>
using namespace std;
int n,m,k;
const int iniNum=50;
const int maxn=1005;
const float pai=acos(-1);
struct node{
    float x,y,val;
}pos[maxn],initSeq[iniNum+5];


float Rand(float L,float R)//产生L到R之间的随机数
{
    return (rand()%10000)/10000.0*(R-L)+L;
}


float dis(node a)
{
    float ans=1000000;
    for(int i=0;i<k;i++)
        ans=min(ans,(float)sqrt((a.x-pos[i].x)*(a.x-pos[i].x)+(a.y-pos[i].y)*(a.y-pos[i].y)));
    return ans;
}
void init()//产生初始点位置,val是距离所有点中的最小值
{
    //printf("initial place:\n");


    for(int i=0;i<iniNum;i++)
    {
        float x=Rand(0,n);
        float y=Rand(0,m);
        initSeq[i].x=x;
        initSeq[i].y=y;
        initSeq[i].val=dis(initSeq[i]);
        //printf("x: %.2f y:%.2f\n",x,y);
    }
}
node nextSolution(node cur,float step)//更新后的点
{
    node next;
    float theta=Rand(0,2*pai);//以任意角度更新
    next.x=cur.x+cos(theta)*step;
    next.y=cur.y+sin(theta)*step;
    while(next.x<0||next.x>n)
    {
        theta=Rand(0,2*pai);
        next.x=cur.x+cos(theta)*step;
    }


    while(next.y<0||next.y>m)
    {
        theta=Rand(0,2*pai);
        next.y=cur.y+sin(theta)*step;
    }


    return next;
}
int sa()
{
    float T=1000,delta=0.98,t_min=0.0001;//初始温度和退火的速率
    float t=T;
    while(t>t_min)
    {
        for(int i=0;i<iniNum;i++)
        {
            node next=nextSolution(initSeq[i],t);
            if(dis(next)>dis(initSeq[i]))//往高处走,直接替换
                initSeq[i]=next;
            else//往低处走,以概率替换
            {
                float p,r,q;
                r=dis(next)-dis(initSeq[i]);//<0
                p=1/(1+exp(r/T));
                //printf("p: %.2f\n",p);
                q=Rand(0.5,1);//因为p的范围是在(0.5,1)内
                if(p>q)//接受
                    initSeq[i]=next;
            }
        }
        t*=delta;
    }
    float ans=dis(initSeq[0]),ans_i=0;
    for(int i=1;i<iniNum;i++)
    {
        //printf("test:\n");
        //printf("x:%.2f  y:%.2f\n",initSeq[i].x,initSeq[i].y);
        if(ans<dis(initSeq[i]))
        {
            ans_i=i;
            ans=dis(initSeq[i]);
        }
    }
    return ans_i;


}
int main()
{
    int T;
    cin>>T;
    srand((unsigned)(time(NULL)));
    while(T--)
    {
        cin>>n>>m>>k;
        for(int i=0;i<k;i++)
            scanf("%f%f",&pos[i].x,&pos[i].y);
        init();//初始化随机点
        int ans_i=sa();
        printf("The safest point is (%.1f, %.1f).\n",initSeq[ans_i].x,initSeq[ans_i].y);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值