Skip to content

Repository files navigation

ball_in_box

This program is used to solve a algorithm problem.

The detailed description is that in a given box by [-1,1], given m balloons(they cannot overlap) with variable radio r and position mu, some tiny blocks are in the box at given posiion {d}, which balloons cannot overlap with, we should find the optimal value of r nd mu which maxmizes sum r^2.

题目翻译:给定一个矩形区域,x 的范围为 (-1, 1), y 的范围为 (-1, 1),同时在这个矩形区域中有 m 个 blocker点,现需要求得 n 个圆,使这 n 个圆的面积和最大,n 个圆满足如下约束:

  • 圆必须在矩形区域内
  • 圆内不得包含任意一个 blocker点, 可以在圆上
  • n 个圆之间不能互相相交, 可以相切

本题选取算法:算法三

算法一

时间复杂度:O(percision) # percision 精度

算法思想:暴力贪婪算法

算法概述:

  • 将给出的矩形区域按照精度(percision) 划分为均匀区域,记 dots 为这些区域的交点

  • 遍历 dots 取出最大圆

    最大的圆的获取方法:dot 到边界,到blockers 的距离中最小的一个即为最大的圆的半径

  • 循环 n 次

缺点:不言而喻

算法二

算法思想:模拟退火算法

爬山算法:

​ 思想:每次从当前解的临近解空间中选择一个最优解作为当前解,直到达到一个局部最优解。

​ 缺点:可能陷入局部最优解,不一定能搜索到全局最优解

​ 如图1所示:假设C点为当前解,爬山算法搜索到A点这个局部最优解就会停止搜索,因为在A点无论向那个方向小幅度移动都不能得到更优的解。

img

模拟退火算法:

​ 思想:模拟退火算法以爬山算法为基础,但是以一定的概率来接受一个比当前解要差的解,因此有可能会跳出这个局部的最优解,从而达到全局的最优解。

​ 如上图示例,模拟退火算法在搜索到局部最优解A后,会以一定的概率接受到E的移动。也许经过几次这样的不是局部最优的移动后可能会到达D点,于是就跳出了局部最大值A。

​ 模拟退火算法描述:

​ 若移动后得到更优解,则总是接受该移动

​ 若移动后的解比当前解要差,则以一定的概率接受移动,而且这个概率随着时间推移逐渐降低(逐渐降低才能趋向稳定)

  这里的“一定的概率”的计算参考了金属冶炼的退火过程,这也是模拟退火算法名称的由来。

  根据热力学的原理,在温度为T时,出现能量差为dE的降温的概率为P(dE),表示为:

    P(dE) = exp( dE/(kT) )

  其中k是一个常数,exp表示自然指数,且dE<0。这条公式说白了就是:温度越高,出现一次能量差为dE的降温的概率就越大;温度越低,则出现降温的概率就越小。又由于dE总是小于0(否则就不叫退火了),因此dE/kT < 0 ,所以P(dE)的函数取值范围是(0,1) 。

  随着温度T的降低,P(dE)会逐渐降低。

  我们将一次向较差解的移动看做一次温度跳变过程,我们以概率P(dE)来接受这样的移动。

本题中只需要首先随机选取一个出发点,之后在一定范围(设定预定参数)内进行模拟退火算法即可获取最大圆

缺点:不如暴力求解精度高

优点:由于引入随机因子,时间复杂度大大减少

算法三

时间复杂度:O(1)

算法概述:

圆是如何确定的?

  • 三点确定一个圆
  • 两点一条切线确定一个圆
  • 一点两条切线确定一个圆
  • 三条切线确定一个圆

综合:

其实以上四种情况可以归结为一种情况:

若要确定圆A,只需给出与A相切的三个圆B, C, D即可

公式如下:

( x - x1)^2^ + ( y - y1)^2^ = ( r + r1)^2^ ( x - x2)^2^ + ( y - y2)^2^ = ( r + r2)^2^ ( x - x3)^2^ + ( y - y3)^2^ = ( r + r3)^2^

三个方程三个未知数即可求解出 唯一的 (x, y, r)

注:一个点可看做一个半径为 0 的圆,一条切线可看做半径无穷大的圆

条件分析:

题目中给出了一个矩形区域,以及 m 个 blocker点

于是初始条件如下:

  • 四个半径无穷大的圆

    # config.py
    # BORDER 假定为无穷大
    BORDER = 1e20 
    # 格式:(x, y, r)
    CONDITIONS = [
        (-BORDER, 0.0, BORDER),
        (BORDER, 0.0, BORDER),
        (0.0, -BORDER, BORDER),
        (0.0, BORDER, BORDER),
    ]
  • m 个半径为 0 的圆

    CONDITIONS = [
       (blocker[0], blocker[1], 0) for blocker in blockers
    ]

解题过程:

  • n 次循环 (n 为要求求出的圆的个数)
  • 在给出的条件中每次抽取 三个,一共有 Cm+4 ^3^ = (m+4) * (m+3) * (m+2) 种组合
  • 利用三个条件圆确定一个圆
  • 每次比较,保存最大的圆
  • 一次循环之后 确定的圆也就成为条件之一,故需要将确定的圆也加入到条件中
  • 如此循环 n 次即可

注:对于半径为无穷大的圆在方程中需要特殊处理

About

软件工程上机实验

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages