1. 题目

圆内任取四点在同一半圆内的概率是多少?
设点出现在圆内任意位置概率均等,且各点在同一直径上也视为在同一半圆内。
一些解答可以参考知乎
我这里写的是我用C++计算概率的一些思路。通过循环来模拟出现的次数,主要书写算法实现产生随机四个点和判断四个点位置的过程。

2. 程序大致流程

  1. 随机产生四个点,并且这些点都在半径为1的圆内;
  2. 计算这些点在不在同一半圆;
  3. 如果是,则num++;
  4. 循环上述步骤一定次数;
  5. 计算出概率num/循环的次数

3. 步骤详解

3.1 产生随机的点

我用vector容器来存储点的横坐标和纵坐标, 关于产生随机数如何在C++中产生随机数这篇博客有详细的介绍,以及c语言如何产生0到 2Π 的随机相位生成在圆内的点,特别注意的是产生随机数种子的srand((unsigned)time(NULL));语句一定要放在循环的最上面。

3.2. 判断四个点是否同一半圆

关于三个点在不在同一半圆,只需判断三个点围成的三角形包不包含圆心;关于四个点,只需任意三个点都共半圆,那么这四个点一定共半圆。具体的证明:求解四只鸭子在同一半圆池塘的概率。因此问题将降解成了判断点在三角形内部还是外部的问题
判断点在三角形内外部的方法主要有内角和法和同向法,同向法的核心是向量叉乘。

叉乘(2维)

  1. 向量模式下
    方向:右手螺旋定则
    模长:| a × b | = |a| ∙ |b| ∙sin⁡(θ) (0°<θ <180°)
  2. 坐标模式下
    A(x1, y1), B(x2, y2) -> a × b = x1 ∙ y2 - y1 ∙ x2
    方向:大于0朝外,小于0朝里
    模长:| x1 ∙ y2 - y1 ∙ x2 |

具体可参考二维向量叉乘公式以及向量积.

拿下图所示的三角形ABC为例,,以a->b->c的顺序绕着三角形走一圈,p点始终在左边,然而q点在走c->a这条路径的时候,在线段的右边。而点在线段(向量)的右边还是左边可以根据叉乘进行判断。
在这里插入图片描述

对于在三角形外部的点,必定与三角形一条边叉乘出来的值与其他两条边方向不同。点是随机取的,所以这条边是无法确定的,因此当三条边叉乘的值都为同号时可以判断点在三角形的圆内,四个点不在同一半圆内。

4. 代码

#include <iostream>
#include <vector>
#include <cmath>
#include<cstdlib>
#include<ctime>
using namespace std;

#define PI 3.1416

vector<double> setValue(void) {
    vector<double> v(2);
    do {
        v[0] = cos(2*rand()*PI/RAND_MAX);
        v[1] = sin(2*rand()*PI/RAND_MAX);
    }while(v[0] * v[0] + v[1] * v[1] > 1 && v[0] != 0 && v[1] != 0);
    return v;
}
bool beyondTriangle(vector<double> a, vector<double> b, vector<double> c) {
 
    double abPlusca = (b[0]-a[0])*(a[1]-c[1]) - (b[1]-a[1])*(a[0]-c[0]);
    double abPluspa = (b[0]-a[0])*(a[1]) - (b[1]-a[1])*(a[0]);
    double orientation1 = abPlusca * abPluspa;

    double bcPlusab = (c[0]-b[0])*(b[1] - a[1]) - (c[1]-b[1])*(b[0] - a[0]);
    double bcPluspb = (c[0]-b[0])*(b[1]) - (c[1]-b[1])*(b[0]);
    double orientation2 = bcPlusab * bcPluspb;

    double caPlusbc = (a[0]-c[0])*(c[1]-b[1]) - (a[1]-c[1])*(c[0]-b[0]);
    double caPluscp = (a[0]-c[0])*(c[1]) - ((a[1]-c[1])*(c[0]));
    double orientation3 = caPlusbc * caPluscp;
    if(orientation1 > 0) {
        if(orientation2 > 0 && orientation3 > 0 ) {
            return false;
        }
    } else if(orientation1 < 0) {
        if(orientation2 < 0 && orientation3 < 0 ) {
            return false;
        }
    }
   return true;
}

int main() {
    int num = 0;
    vector<double> a, b, c, d;
    srand((unsigned)time(NULL));
    for(int i = 0; i < 5; i++) {
        num = 0;
        
        for(int i = 0; i < 10000; i++) {  
            
            a = setValue();   
            b = setValue();
            c = setValue();
            d = setValue();
            if(beyondTriangle(a, b, c) && beyondTriangle(a, b, d) && beyondTriangle(b, c, d)) {
                num++;
            }
        }
        cout << (double)num/10000 << endl;
    }
    return 0;
}

5. 某次数据较好的测试结果

在这里插入图片描述

主参考

求解四只鸭子在同一半圆池塘的概率.

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐