HDOJ HDU 1109 Run Away

本文通过解决HDOJ1109RunAway问题,详细介绍了模拟退火算法的基本原理及应用。通过随机选取多个初始解并逐步逼近最优解的方式,实现了寻找最安全点的任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HDOJ 1109 Run Away

题目

点此查看 HDOJ 1109 Run Away

分类

模拟 模拟退火
我自己是没有想到解法的 看到别人的解法 学习了 模拟退火

题意

地上有 n 个陷阱
距离陷阱越远越安全
求 最安全的点

题意

先看 模拟退火
说说 我的理解
在加热时 分子会散开 而 在逐渐冷却时 分子会渐渐缩小行动范围 直到 到达固定的位置
在此过程中 有两个重要过程
第一 加热 其实就是 让 各个答案(分子) 随机的分布开
第二 冷却 其实所选的 答案慢慢在减小的活动范围内选择最佳解

举个例子 借鉴一下 苍梧 的 大白话解析模拟退火算法
爬山算法 图示
找出最高峰(人会走到最近的峰)
先 随机选取 n 个点 例如选了 C C 看到 A最高
确定一个步长,让C到步长的点瞬移例如 D 另一个瞬移到E
慢慢冷却 (减小步长) E,D 以步长乱移
最终 各点 将 到达最高峰 选出最高即可

我的理解是 利用随机 和 概率
随机很多个局部解(有很多分子被加热)
让 局部解 慢慢接近局部最优解(冷却)
如果 随机解(分子)很多的情况下 按照概率 ,几乎没有可能不找到最优解
再看这道题
我们先 随机 50个(参考其他人选的,这个值比较合适(够准确,而且没有必要跟多)) 点 (加热)
然后 以这 50个 点 以 step步长乱移 50(这个值比较合适)次 如果 比当前安全 就换到哪里
减小步长 重复上述过程 直到 需要的精度

代码

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <cmath>

#define M_PI 3.14159265358979323846
#define inf 0x7fffffff
#define end 0.001
// 精度
#define df 0.85
// 冷却幅度 (步长减小幅度) 
#define maxn 1000
#define maxit 30

using namespace std;

int mx,my;
double fx[maxn],fy[maxn],best[maxn],px[maxn],py[maxn];

double randr(double l,double r);
//随机在 l 到 r 的区间中 取一个值 
double dist(double x1,double y1,double x2,double y2);
//欧几里得距离

int main()
{
    srand(time(NULL));
    int t,n,res;
    cin >> t;
    while(t--)
    {
        cin >> mx >> my >> n;
        for(int i = 0;i < n;i++)
        {
            cin >> px[i] >> py[i]; 
        }

        for(int i = 0;i < maxit;i++)
        {
            fx[i] = randr(1,mx);
            fy[i] = randr(1,my);
          //加热 乱选50个点
            best[i] = inf;
            for(int j = 0;j < n;j++)
            {
                best[i] = min(best[i],dist(fx[i],fy[i],px[j],py[j]));
            }
        }
        double step = max(mx,my);
         //初始步长为 矩形的长
        while(step > end)
        {
            for(int i = 0;i < maxit;i++)
                for(int j = 0;j < maxit;j++)
                {
                    double ag = randr(0,2 * M_PI);
                    double nx = fx[i] + step * cos(ag);
                    double ny = fy[i] + step * sin(ag);
                    // 在冷却范围内乱动
                    if(nx < 0 || ny < 0 || nx > mx || ny > my)
                        continue;
                    double d = inf;
                    for(int k = 0;k < n;k++)
                    {
                        d = min(d,dist(nx,ny,px[k],py[k]));
                    }
                    if(d > best[i])
                    {
                        best[i] = d;
                        fx[i] = nx;
                        fy[i] = ny;
                    }
                    // 移动到更安全的位置
                }
            step *= df;
        }
        res = 0;
        for(int i = 1;i < maxit;i++)
        {
            if(best[i] >= best[res])
            {
                res = i;
            }
        }
        cout << setiosflags(ios::fixed) << setprecision(1) << "The safest point is (" << fx[res] << ", " << fy[res] << ")." << endl;
    }
    return 0;
}

double randr(double l,double r)
{
    return (rand() % 10000) / 10000.0 *(r-l) + l;
}

double dist(double x1,double y1,double x2,double y2)
{
    return sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值