趣味算法 四个点在同一个半圆的概率
1. 题目圆内任取四点在同一半圆内的概率是多少?设点出现在圆内任意位置概率均等,且各点在同一直径上也视为在同一半圆内。一些解答可以参考知乎。我这里写的是我在用C++写出计算概率的一些思路。通过循环来模拟出现的次数,主要书写算法实现产生随机四个点和判断四个点的过程。2. 程序大致流程随机产生四个点,并且这些点都在半径为1的圆内;计算这些点在不在同一半圆;如果是,则num++;重复上述步骤一定次数;计
1. 题目
圆内任取四点在同一半圆内的概率是多少?
设点出现在圆内任意位置概率均等,且各点在同一直径上也视为在同一半圆内。
一些解答可以参考知乎。
我这里写的是我用C++计算概率的一些思路。通过循环来模拟出现的次数,主要书写算法实现产生随机四个点和判断四个点位置的过程。
2. 程序大致流程
- 随机产生四个点,并且这些点都在半径为1的圆内;
- 计算这些点在不在同一半圆;
- 如果是,则
num++; - 循环上述步骤一定次数;
- 计算出概率
num/循环的次数。
3. 步骤详解
3.1 产生随机的点
我用vector容器来存储点的横坐标和纵坐标, 关于产生随机数如何在C++中产生随机数这篇博客有详细的介绍,以及c语言如何产生0到 2Π 的随机相位生成在圆内的点,特别注意的是产生随机数种子的srand((unsigned)time(NULL));语句一定要放在循环的最上面。
3.2. 判断四个点是否同一半圆
关于三个点在不在同一半圆,只需判断三个点围成的三角形包不包含圆心;关于四个点,只需任意三个点都共半圆,那么这四个点一定共半圆。具体的证明:求解四只鸭子在同一半圆池塘的概率。因此问题将降解成了判断点在三角形内部还是外部的问题。
判断点在三角形内外部的方法主要有内角和法和同向法,同向法的核心是向量叉乘。
叉乘(2维)
- 向量模式下
方向:右手螺旋定则
模长:| a × b | = |a| ∙ |b| ∙sin(θ) (0°<θ <180°)- 坐标模式下
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. 某次数据较好的测试结果

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


所有评论(0)