最近我发现了一个有趣的问题,问题如上。问题简化一下,大概就是一圆内有四个随机生成的点,求四个点在同一半圆的概率。

问题分析:

  1. 怎么判断四点是否在同一半圆内?
  2. 怎么判断一个点是否在一个凸多边形内?
  3. 怎么通过四个点生成一个凸多边形?
  4. 怎么定量判断一点是否在一个三角形内?

先解决第一个问题,那我们都知道,任意一天圆的直径都能将一个圆平分,而任意一条直径都过圆心,所以只要圆心不在四点所围成的凸多边形,那为什么是凸多边形呢?后面会有解答。

解决第一个问题后,随之衍生出第二个问题,先明确凸多边形是啥意思?凸多边形(Convex Polygon)指如果把一个多边形的所有边中,任意一条边向两方无限延长成为一直线时,其他各边都在此直线的同旁,那么这个多边形就叫做凸多边形。简单的说,就是内角都得小于180才叫凸多边形。

再看一什么是非凸多边形

可以看到,图中圆内四点所形成的就是一个非凸多边形,此时圆心确实也在该多边形的外面,但是却不能找到一条直径让这四点分布在同一侧,所以我们强调要凸多边形。

解决了上述问题,那就要思考一下给四个点怎么能生成一个凸多边形?我就想到,任一多边形都能由几个三角形拼接而成。所以,任给四个点,我们可以先生成C43也就是4个三角形,然后把这四个三角形围成的区域并起来就可以形成一个凸多边形,当然后面也证实这确实是我们所需要的凸多边形。类似下面这样。

上图中,圆内四点ABCD,圆心O,然后是有ABC,ABD,ACD,BCD四个三角形,可以看到这四个三角形区域并起来围成的区域是三角形ABD,圆心位于该多边形内(三角形也是凸多边形),这时就得到了正确的结论。

到现在问题已经转化到如何判断一点是否在一个三角形内了。因为,圆内生成的四点可以三三生成四个三角形,那么我们只需要保证圆心不在任意一个生成的三角形内就可以保证该四点可被一条直径划分到同一侧,即全部分布在一个半圆内。当然相反地,圆心只要分布在至少一个三角形内就说明没有一条直径能够将这四点划分在同一侧,即非全部分布在一个半圆内。那么到底该怎么判断勒?看下图

上图呢,是一个任意的三角形ABC和内外两点P1,P2,将P1,P2都与三角形的三个顶点相连又可以得到三个三角形,观察得到,内点P1形成的三个三角形面积之和就等于ABC的面积,而外点P2形成的三个三角形面积之和比ABC的面积大一个P2BC的面积。所以得出结论就是只需要计算点与三角形顶点所形成的三个三角形面积之和再与原三角形面积比较即可得到该点是否在三角形内。

写到这里,如果不用概率论与数理统计的知识去解决,而单纯的用计算机模拟的话,问题已经变得很简单了。继问题四往后推,也就是需要实现一个求三角形面积的函数,实现如下

double Striangle(double *A,double *B,double *C){//输入三点ABC坐标(二维数组)//输出所围三角形面积double deta_x1,deta_x2,deta_y1,deta_y2;double Ax,Ay,Bx,By,Cx,Cy;double len_a,len_b,sineC;double S=-1;Ax=A[0];Ay=A[1];Bx=B[0];By=B[1];Cx=C[0];Cy=C[1];deta_x1=(Ax-Bx);deta_x2=(Ax-Cx);deta_y1=(Ay-By);deta_y2=(Ay-Cy);if(deta_x1*deta_x2!=0 && deta_y1/deta_x1==deta_y2/deta_x2) {return 0;} else if(deta_x1==0 && deta_y1==0) {return 0;} else if(deta_x2==0 && deta_y2==0) {return 0;} else {len_a=length(B,C);len_b=length(A,C);sineC=sine_angle(A,B,C);S=0.5*len_a*len_b*sineC;return S;}}

可以看到在运行这个函数之前,还需要再实现两个函数求两点距离和三角形某个角正弦值,实现如下

double length(double *A,double *B){//输入两点AB坐标(二维数组)//输出两点距离(模长)double Ax,Ay,Bx,By,R;Ax=A[0];Ay=A[1];Bx=B[0];By=B[1];R=sqrt(pow(Ax-Bx,2) + pow(Ay-By,2));return R;}double sine_angle(double *A,double *B,double *C){//输入三点ABC坐标(二维数组)//输出角C的正弦值double len_a,len_b,len_c;double cosine2ab,cosine,sine;len_a=length(B,C);len_b=length(A,C);len_c=length(A,B);cosine2ab=pow(len_a,2)+pow(len_b,2)-pow(len_c,2);if(len_a*len_b!=0) {cosine=cosine2ab / (2*len_a*len_b);} else {cosine=1;}sine=sqrt(1-pow(cosine,2));return sine;}

到这里就没啥难度了,下面再说一下怎么随机生成四点坐标,实现如下

void rand_circle_coord(*CC){//输入一个空二维数组//将随机数赋值给传入的指针//srand(time(0));CC[0]=rand()%(2*eps+1) - eps;CC[1]=rand()%(2*eps+1) - eps;}void rand_circle_coords(double *A,double *B,double *C,double *D){//输入四个二维数组//将随机坐标复制给传入的四个指针int intA[2],intB[2],intC[2],intD[2];double O[2]= {0,0};//srand(time(0));rand_circle_coord(intA);A[0]=intA[0] / (double)eps;A[1]=intA[1] / (double)eps;while(length(A,O)>=1.00) {rand_circle_coord(intA);A[0]=intA[0] / (double)eps;A[1]=intA[1] / (double)eps;}//printf("A是(%lf,%lf)\n",A[0],A[1]);rand_circle_coord(intB);B[0]=intB[0] / (double)eps;B[1]=intB[1] / (double)eps;while(length(A,O)>=1.00) {rand_circle_coord(intB);B[0]=intB[0] / (double)eps;B[1]=intB[1] / (double)eps;}//printf("B是(%lf,%lf)\n",B[0],B[1]);rand_circle_coord(intC);C[0]=intC[0] / (double)eps;C[1]=intC[1] / (double)eps;while(length(C,O)>=1.00) {rand_circle_coord(intC);C[0]=intC[0] / (double)eps;C[1]=intC[1] / (double)eps;}//printf("C是(%lf,%lf)\n",C[0],C[1]);rand_circle_coord(intD);D[0]=intD[0] / (double)eps;D[1]=intD[1] / (double)eps;while(length(D,O)>=1.00) {rand_circle_coord(intD);D[0]=intD[0] / (double)eps;D[1]=intD[1] / (double)eps;}//printf("D是(%lf,%lf)\n",D[0],D[1]);}

到这里基本的一些函数就全部实现好了,剩下的就是将这些函数联合起来用,达到模拟的效果,整个代码如下

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>#define eps 1000000double length(double *A,double *B);
double sine_angle(double *A,double *B,double *C);
double Striangle(double *A,double *B,double *C);
int judgeP_in_triangle(double *A,double *B,double *C,double *P);
int judgeO_in_triangles(double *A,double *B,double *C,double *D);
void rand_circle_coord(int *CC);
void rand_circle_coords(double *A,double *B,double *C,double *D);int main()
{double A[2];double B[2];double C[2];double D[2];int i,j,P=0,R[100],epochs=1000;srand(time(0));for(j=0; j<100; j++) {R[j]=0;for(i=0; i<epochs; i++) {rand_circle_coords(A,B,C,D);if(judgeO_in_triangles(A,B,C,D)) {R[j]+=1;}}}for(j=0;j<100;j++){P+=R[j];}printf("\n结果是%lf",(double)P / (epochs*100));return 0;
}double length(double *A,double *B)
{//输入两点AB坐标(二维数组)//输出两点距离(模长)double Ax,Ay,Bx,By,R;Ax=A[0];Ay=A[1];Bx=B[0];By=B[1];R=sqrt(pow(Ax-Bx,2) + pow(Ay-By,2));return R;
}double sine_angle(double *A,double *B,double *C)
{//输入三点ABC坐标(二维数组)//输出角C的正弦值double len_a,len_b,len_c;double cosine2ab,cosine,sine;len_a=length(B,C);len_b=length(A,C);len_c=length(A,B);cosine2ab=pow(len_a,2)+pow(len_b,2)-pow(len_c,2);if(len_a*len_b!=0) {cosine=cosine2ab / (2*len_a*len_b);} else {cosine=1;}sine=sqrt(1-pow(cosine,2));return sine;
}double Striangle(double *A,double *B,double *C)
{//输入三点ABC坐标(二维数组)//输出所围三角形面积double deta_x1,deta_x2,deta_y1,deta_y2;double Ax,Ay,Bx,By,Cx,Cy;double len_a,len_b,sineC;double S=-1;Ax=A[0];Ay=A[1];Bx=B[0];By=B[1];Cx=C[0];Cy=C[1];deta_x1=(Ax-Bx);deta_x2=(Ax-Cx);deta_y1=(Ay-By);deta_y2=(Ay-Cy);if(deta_x1*deta_x2!=0 && deta_y1/deta_x1==deta_y2/deta_x2) {return 0;} else if(deta_x1==0 && deta_y1==0) {return 0;} else if(deta_x2==0 && deta_y2==0) {return 0;} else {len_a=length(B,C);len_b=length(A,C);sineC=sine_angle(A,B,C);S=0.5*len_a*len_b*sineC;return S;}
}int judgeP_in_triangle(double *A,double *B,double *C,double *P)
{int flag;double Spab,Spac,Spbc,Sabc,deta_S;Spab=Striangle(A,B,P);Spac=Striangle(A,C,P);Spbc=Striangle(B,C,P);Sabc=Striangle(A,B,C);deta_S=Spab+Spac+Spbc-Sabc;if(deta_S<=1e-06) {flag=1;} else {flag=0;}return flag;
}int judgeO_in_triangles(double *A,double *B,double *C,double *D)
{double O[2]= {0,0};int flag1,flag2,flag3,flag4;flag1=!judgeP_in_triangle(A,B,C,O);flag2=!judgeP_in_triangle(A,B,D,O);flag3=!judgeP_in_triangle(A,C,D,O);flag4=!judgeP_in_triangle(B,C,D,O);if(flag1 && flag2 && flag3 && flag4) {return 1;} else {return 0;}
}void rand_circle_coord(int *CC)
{//输入一个空二维数组//将随机数赋值给传入的指针//srand(time(0));CC[0]=rand()%(2*eps+1) - eps;CC[1]=rand()%(2*eps+1) - eps;
}void rand_circle_coords(double *A,double *B,double *C,double *D)
{//输入四个二维数组//将随机坐标复制给传入的四个指针int intA[2],intB[2],intC[2],intD[2];double O[2]= {0,0};//srand(time(0));rand_circle_coord(intA);A[0]=intA[0] / (double)eps;A[1]=intA[1] / (double)eps;while(length(A,O)>=1.00) {rand_circle_coord(intA);A[0]=intA[0] / (double)eps;A[1]=intA[1] / (double)eps;}//printf("A是(%lf,%lf)\n",A[0],A[1]);rand_circle_coord(intB);B[0]=intB[0] / (double)eps;B[1]=intB[1] / (double)eps;while(length(A,O)>=1.00) {rand_circle_coord(intB);B[0]=intB[0] / (double)eps;B[1]=intB[1] / (double)eps;}//printf("B是(%lf,%lf)\n",B[0],B[1]);rand_circle_coord(intC);C[0]=intC[0] / (double)eps;C[1]=intC[1] / (double)eps;while(length(C,O)>=1.00) {rand_circle_coord(intC);C[0]=intC[0] / (double)eps;C[1]=intC[1] / (double)eps;}//printf("C是(%lf,%lf)\n",C[0],C[1]);rand_circle_coord(intD);D[0]=intD[0] / (double)eps;D[1]=intD[1] / (double)eps;while(length(D,O)>=1.00) {rand_circle_coord(intD);D[0]=intD[0] / (double)eps;D[1]=intD[1] / (double)eps;}//printf("D是(%lf,%lf)\n",D[0],D[1]);
}

这里我们模拟1000次,重复实验100次然后取平均结果如下

大概是0.5的概率,一半一半吧。

好了。整个问题我的想法就是这样了。如有错误欢迎指正,一起进步,加油

一个有趣的问题(随缘更新)相关推荐

  1. python函数type的用意_Python内置函数Type()函数一个有趣的用法

    Python内置函数Type()函数一个有趣的用法 今天在网上看到type的一段代码 ,然后查了一下文档,才知道type还有三个参数的用法. 以前只是知道type可以检测对象类型.然后发现了一个有趣的 ...

  2. 给小孩发布一个有趣的网站 在线动物园

    给小孩发布一个有趣的网站 在线动物园,可以实时看到动物园里的动物实时摄像头. 非常有意思,大热天也不用到动物园里看了. http://zoo.baidu.com/video.html

  3. 一个有趣的实验:用0.1f 替换 0,性能提升 7 倍!

    点击关注上方"视学算法",设为"置顶或星标",第一时间送达技术干货. 本文来源:http://cenalulu.github.io/linux/about-de ...

  4. 一个有趣的小例子,带你入门协程模块-asyncio

    上篇文章写了关于yield from的用法,简单的了解异步模式,[上次的内容链接]这次让我们通过一个有趣例子带大家了解asyncio基本使用. 目标效果图 在控制台中显示一个由ASCII字符" ...

  5. 这是一个有趣的问题,Java 8 Lambda 表达式被编译成了什么?

    在了解了Java 8 Lambda的一些基本概念和应用后, 我们会有这样的一个问题: Lambda表达式被编译成了什么? 这是一个有趣的问题,涉及到JDK的具体的实现.本文将介绍OpenJDK对Lam ...

  6. union一个有趣的应用

    今天在读<Linux高性能服务器编程>时看到一个有趣的东西.书中用了一个特别的方法去求字节序.我们知道字节序分为大端和小端,大端就是数据的高位字节存储在内存的低地址处,小段则反之.那么我们 ...

  7. 分享一个有趣的学习方法,欢迎一起探讨如何提高学习兴趣作者:1-2-3 来源:博客园 发布时间:2009-03-09 16:20 阅读:2820 次 原文链接 [收藏]

    分享一个有趣的学习方法,欢迎一起探讨如何提高学习兴趣 作者:1-2-3  来源:博客园  发布时间:2009-03-09 16:20  阅读:2820 次  原文链接   [收藏]   有些人似乎天生 ...

  8. 编写一个弹出式菜单的shell程序_分享一个有趣的shell脚本--实现抓阄程序

    概述 今天主要分享一个有趣的shell脚本,用来实现抓阄,平时就不用剪刀石头布了. 需求 使用shell编写一个抓阄的程序: 1.执行脚本后,输入英文名字全拼,产生随机数01-99之间的数字,数字越大 ...

  9. firebug的一个有趣现象

    firebug的一个有趣现象 var obj = {length:0,splice:function(){}}console.log(obj) 猜猜上面会打印出啥? 没错,打印出来的看起来是一个空数组 ...

最新文章

  1. 服务器返回数据为空,iOS 处理服务器返回数据中的null
  2. Spring中使用@ModelAttribute注解
  3. 五分钟精通Oracle Hints
  4. matlab里面filename1,matlab 每次从一个txt文件(里面每行是一个图像名字,如1.jpg之类的)读取一行字符串...
  5. 如何在MATLAB中把变量填到Word中,matlab数据写入现有excel表格-如何将matlab中变量写入excel...
  6. sql 除法_七天学会SQL-04SQL复杂查询
  7. Visual C++ 基础数据类型的转换
  8. CSS控制文本超出指定宽度显示省略号和文本不换行
  9. c++ 图片验证码识别_图片验证码识别方法
  10. 《宗教与科学》——罗素 读书笔记
  11. 找不到战网服务器ip地址,wow服务器ip地址-我怎么知道战网服务器的IP地址去PING, – 手机爱问...
  12. [智慧园区]之访客应用
  13. 利用 visitor map (访客地图) 统计网站访客
  14. pet 计算机术语,计算机专业英语翻译1?计算机专业英语翻译1、Tobecompet 爱问知识人...
  15. 绿色手动安装MySQL数据库
  16. c++ IO流---输入输出流 格式控制字符
  17. 用科傻软件,求平面网和高程网的平差
  18. 肖秀荣:考研政治选择题最完整答题技巧总结
  19. 机器人企业如何在激流勇进的市场中,深耕落地,突出重围?
  20. 微信小程序(游戏)----拼图游戏(设计思路)

热门文章

  1. 湍流系数计算器_雷诺数Re计算公式与在线计算器_三贝计算网_23bei.com
  2. 洛谷入门题单 --【入门1】顺序结构 题解
  3. 格式化磁盘时文件系统格式选择
  4. 面经+经验分享|2019秋招算法岗复盘
  5. 华硕Tinker Board开发板(rk3288处理器)开发 ---- 在Android7.1.2中某个apk项目中添加LOGD,LOGE等调试打印功能
  6. python爬贴吧回复_通过python爬取贴吧数据并保存为word
  7. 对话阿里云崔昊:在线教育市场的变与不变?
  8. This is life
  9. 2014年新年新气象
  10. 微分算子法在平时考试的应用