姗姗来迟的挑战(四)

说在前面

题目背后的故事

早在本蒟蒻还没有退役的时候,yuzan1830就已经酝酿好了题目。鉴于本蒟蒻的水瓶水平,当时题目没有解决。于是非常无情地,这道题被咕掉了。

题目原型是这样的:平面内有一些圆,每个圆有一定的半径。圆的位置可以移动,但不能有重叠。现在需要在平面内找到一个矩形,使得这些圆都在矩形内,且矩形的面积最小。求最小面积。yuzan1830并不喜欢特别多的输入,于是他只给出了半径为某个值的圆的数量,而不是给出每个圆的半径。

这里不讨论过去一年的时间里yuzan1830是如何破茧成蝶、寻找成长的价值,以及本蒟蒻是如何放弃挑战、走向自闭的深渊, 现在直接进入正题:模拟退火

重拾挑战

模拟退火的核心是以一定概率接受随机产生的新解。以求函数 f ( x ) f(x) 的最小值为例,这个概率为( T T 为当前的温度):

p = { 1 Δ f < 0 e Δ f T Δ f 0 p=\begin{cases} 1&\Delta f<0\\ e^{\frac{-\Delta f}T}&\Delta f\geqslant 0 \end{cases}

除此之外就是如何产生新解以及调参的问题。

本题最大的问题是圆的位置不确定。不过用上模拟退火就显得简单粗暴了,将矩形的面积看成是关于圆的位置集合的一个函数 f ( S ) f(S) S = { ( x i , y i ) } S=\lbrace(x_i,y_i)\rbrace ,随机确定每个圆的位置,然后可以通过求此时矩形的最小面积作为函数值,再用模拟退火求函数 f ( S ) f(S) 的最小值。

在圆的位置确定的情况下求矩形的最小面积成了另一个问题。显然矩形的每条边一定和至少一个圆相切。如果知道了矩形两条邻边的倾斜角 θ 1 , θ 2 \theta_1,\theta_2 ,就可以用两条倾斜角分别为 θ 1 , θ 2 \theta_1,\theta_2 的直线去和每一个圆相切,得到两组平行线,最外边的四条直线围成的图形即为所求矩形。而 θ 1 , θ 2 \theta_1,\theta_2 中一定有一个角在 [ 0 , 9 0 ) [0,90^{\circ}) 范围内(设为 θ \theta ),而另一个角就是 θ + 9 0 \theta+90^{\circ} 。此时矩形的面积又可以看成是关于 θ \theta 的函数 g S ( θ ) g_S(\theta)

然后又用模拟退火求 g S ( θ ) g_S(\theta) 的最小值?没有必要。如果另行作一个函数 f ( S ) = g S ( 0 ) f'(S)=g_S(0) 表示 θ = 0 \theta=0 时矩形的面积1,虽然 θ = 0 \theta=0 时矩形的面积不一定最小,但对问题的最终答案没有影响。考虑把圆的位置集合为 S S 时面积最小的矩形及所有的圆绕原点旋转,保持相对位置不变,旋转到矩形的四条边与坐标轴平行为止。记旋转后圆的位置集合为 S S' ,矩形的倾斜角为 θ \theta' 。于是 θ = 0 \theta'=0 ,那么有

f ( S ) = f ( S ) = f ( S ) f'(S')=f(S')=f(S)

而圆的位置是随机的, f f 函数能取到的值, f f' 函数都能取到。因此只需要求 f ( S ) f'(S) 的最小值作为最终答案,连切线都不需要算了,直接取所有圆的上下左右边界。

初始解设置为所有的圆排成一列。生成新解的时候,随机选择一个圆,随机移动到附近的一个位置,移动的距离随温度下降而减少。如果移动后的圆与其它的圆出现了重叠,简单粗暴地重新生成新解。

TO   BE   CONTINUED... \texttt{TO BE CONTINUED...}


  1. 这里的 f ( S ) f'(S) 不表示 f ( S ) f(S) 的导数。 ↩︎

发布了26 篇原创文章 · 获赞 13 · 访问量 4880

猜你喜欢

转载自blog.csdn.net/PHenning/article/details/105394553