HDU 4978 A simple probability problem. 蒲丰投针问题 + 二维凸包

来源:互联网 发布:5g网络概念股龙头 编辑:程序博客网 时间:2024/04/26 14:55

题目大意:

就是现在有一个平面上铺满了间距为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;}


0 0