原题链接

    题目描述:
    给定圆的半径和圆心的位置,实现函数 randPoint ,在圆中产生均匀随机点。
    实现 Solution 类:
    Solution(double radius, double x_center, double y_center) 用圆的半径 radius 和圆心的位置 (x_center, y_center) 初始化对象
    randPoint() 返回圆内的一个随机点。圆周上的一点被认为在圆内。答案作为数组返回 [x, y] 。

    方法一:拒绝采样
    思路与算法
    拒绝采样的意思是说:我们在一个更大的范围内生成随机数,并拒绝掉那些不在题目给定范围内的随机数,此时保留下来的随机数都是在范围内的。为了在一个半径为 R 的圆中生成均匀随机点,我们可以使用一个边长为 2R的正方形覆盖住圆,并在正方形内生成均匀随机点,此时就只需要对于横坐标和纵坐标分别生成一个随机数即可。若该点落在圆内,我们就返回这个点,否则我们拒绝这个点,重新生成,直到新的随机点落在圆内。

    细节
    由于正方形的面积为 (2R)^2 = 4R^2,圆的面积为 pi R^2,因此在正方形中随机生成的点,落在圆内的概率为
    给定圆心和半径,随机获取圆内一点 - 图1

    在正方形中生成点时(正方形中心的坐标简记为原点),如果我们在 [-R, R)的范围内生成随机数,那么是无法生成到横坐标或纵坐标恰好为 R 的点,对应到圆上时,会有圆周上与正方形边相切的两个点无法随机到。我们可以在生成时稍微提高右边界(例如 2R + ϵ,其中 ϵ 是一个很小的常数,例如 10^{-7}
    ),或者直接忽略这两个点,因为它们的勒贝格测度为零。

    1. using System;
    2. namespace ConsoleApplication1
    3. {
    4. //获取圆内随机的一点 没一点概率相等
    5. //采用拒绝采样方法 用一个长为2r的正方形包围圆 若点不在圆内 则继续随机
    6. //
    7. public class getCirclePoint
    8. {
    9. double _radius; //圆半径
    10. double _xcenter;
    11. double _ycenter;
    12. Random random;
    13. public getCirclePoint(double radius, double x_center, double y_center)
    14. {
    15. _radius = radius;
    16. _xcenter = x_center;
    17. _ycenter = y_center;
    18. random= new Random();
    19. }
    20. public double[] RandPoint()
    21. {
    22. while (true)
    23. {
    24. double x = random.NextDouble() * 2 * _radius - _radius;
    25. double y = random.NextDouble() * 2 * _radius - _radius;
    26. if ((x - _xcenter) * (x - _xcenter) + (y - _ycenter) * (y - _ycenter) < _radius * _radius)
    27. {
    28. return new double[] { x, y };
    29. }
    30. }
    31. }
    32. public double[] mathGetRandPoint()
    33. {
    34. double u = random.NextDouble();
    35. double theta = random.NextDouble() * 2 * Math.PI;
    36. double r = Math.Sqrt(u);
    37. return new double[] { _xcenter + r * Math.Cos(theta) * _radius, _ycenter + r * Math.Sin(theta) * _radius };
    38. }
    39. }
    40. }