题目大意:
就是现在有一个平面上铺满了间距为D的平行直线, 现在有一个圆的直径是D, 将这个圆的中心放在原点处之后给出N( N <= 100)个点的坐标, N个点都在圆上或者圆内, 现在这N个点两两之间都有线段相连, 问如果将这个圆随机地放置到铺满间距为D的平面上, 这N个点之间的连线与平面上的平行线相交的概率, 结果保留小数点后四位
大致思路:
当时看的时候觉得是一个神题, 只会积分手算第一个样例, 后来发现这是一个概率上的结论题
首先需要知道这样一个概率模型:
蒲丰投针问题(Buffon needle problem)
18世纪, 法国数学家布丰和勒克莱尔提出的“投针问题”, 记载于布丰1777年出版的著作中:“在平面上画有一组间距为D的平行线, 将一根长度为L(L < D)的针任意投掷在这个平面上, 求此针与平行线中任一直线相交的概率. 布丰本人证明了这个概率是:
P = 2*L/(π*D)
另外参考有关论文可以发现对于蒲丰投针问题的扩展结论
当投掷物是一般的平面凸曲线时的蒲丰问题 平面内任何一个凸曲线,都可以有一列凸多边形来逼近(当凸多边形的边数趋于无穷大时),在这列凸多边形中取极限的过程,就可得到凸曲线。例如,圆可以由正n边形来逼近(n→∞)。因此,可以不加证明地指出:平面凸曲线的蒲丰问题与凸多边形的蒲丰问题有相同的结果,也就是说,平面上画有等距离D(D>0)的平行线,向平面上任意投掷一个直径为d(d<D)的二维凸曲线,设凸曲线周长为C,则凸曲线与平行线相交的概率为P=C/(π*D)
那么对于本题的思路就很明显了, 如果存在两点的连线与平面上的直线相交, 则这N个点的凸包必定与平面上的直线相交, 如果凸包与直线相交, 必然存在两点连线与平面上的线相交(凸包的边就是N个点中一些点的连线)
所以只需要求出这N个点的凸包的周长然后结合蒲丰投针问题的扩展结论即可求得概率
代码如下:
Result : Accepted Memory : 1120 KB Time : 15 ms
/* * Author: Gatevin * Created Time: 2014/12/27 15:52:34 * File Name: Sora_Kasugano.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; const double PI = acos(-1.0); int sgn(double d) { return d < -eps ? -1 : (d > eps ? 1 : 0);; } struct point { double x, y; point(double _x = 0, double _y = 0) : x(_x), y(_y) {} void input() { scanf("%lf %lf", &x, &y); return; } double len() const { return sqrt(x*x + y*y); } void output() const { printf("%.3f %.3f\n", x, y); } }; point operator + (const point &p1, const point &p2) { return point(p1.x + p2.x, p1.y + p2.y); } point operator - (const point &p1, const point &p2) { return point(p1.x - p2.x, p1.y - p2.y); } double operator ^ (const point &p1, const point &p2) { return p1.x*p2.x + p1.y*p2.y; } double operator * (const point &p1, const point &p2) { return p1.x*p2.y - p2.x*p1.y; } bool operator < (point p1, point p2) { return sgn(p1.x - p2.x) == 0 ? sgn(p1.y - p2.y) < 0 : p1.x < p2.x; } point p[110]; point pol[110]; int dn, hd[110], un, hu[110]; void getConvexHull(point *p, int n, point *pol, int &m)//求二维凸包 { sort(p, p + n); dn = un = 2; hd[0] = hu[0] = 0; hd[1] = hu[1] = 1; for(int i = 2; i < n; i++) { for(; dn > 1 && sgn((p[hd[dn - 1]] - p[hd[dn - 2]]) * (p[i] - p[hd[dn - 1]])) <= 0; dn--); for(; un > 1 && sgn((p[hu[un - 1]] - p[hu[un - 2]]) * (p[i] - p[hu[un - 1]])) >= 0; un--); hd[dn++] = hu[un++] = i; } m = 0; for(int i = 0; i < dn - 1; i++) pol[m++] = p[hd[i]]; for(int i = un - 1; i > 0; i--) pol[m++] = p[hu[i]]; } int main() { int t; scanf("%d", &t); int N, D; int cnt; for(int cas = 1; cas <= t; cas++) { scanf("%d %d", &N, &D); for(int i = 0; i < N; i++) p[i].input(); getConvexHull(p, N, pol, cnt); double C = 0; for(int i = 1; i < cnt; i++) C += (pol[i] - pol[i - 1]).len(); C += (pol[0] - pol[cnt - 1]).len(); double ans = C/(PI*D); printf("Case #%d: %.4f\n", cas, ans); } return 0; }