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));
}