HDU_4978_A simple probability problem.(推导or精度枚举)

来源:互联网 发布:淘宝店铺怎么搜索不到 编辑:程序博客网 时间:2024/05/22 06:14

题型:计算几何


题意:

       一个平面上有无数个相距为D的平行直线,一个直径为D的均匀圆盘上有N个点组成的多边形,随机将圆盘扔在平面上,求平面上的某直线穿过多边形的概率。


分析:

首先分析圆盘上只有一条线段的情况,设线段长为l。若线段与平面上直线垂直,则线段与直线相交的概率如图1


如果旋转一下角度,概率就变为如图2所示


那么随机扔线段与直线相交的概率为


对于n个点,先求一个凸包。

凸包的每一条边与直线相交的概率都是


那么总概率就是概率之和,但是考虑到凸包的一个性质,即:任意一条直线穿过凸包,都会与两条边长相交,所以总概率是


所以求一个凸包周长即可。


但是在比赛过程中,对于我等脑残弱智党来说,推出上述公式简直难,俺们会的就是暴力了。。。

于是想到枚举精度,将180度切成若干分,每次度数加一点算出一个l,随后算一个平均值就是概率。


然后,我就开始暴力提交了,我将180度切成3000分卡过。


公式正解代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#define LL long long#define mt(a,b) memset(a,b,sizeof(a))using namespace std;const double eps = 1e-10;const double PI = acos(-1.0);struct point {    double x,y;} p[123],res[123];int n,d;bool operator < (const point &l, const point &r) {    return l.y < r.y || (fabs(l.y- r.y)<eps && l.x < r.x);}class ConvexHull { //凸包    bool mult(point sp, point ep, point op) {        return (sp.x - op.x) * (ep.y - op.y)>= (ep.x - op.x) * (sp.y - op.y);    }public:    int graham(int n,point p[],point res[]) {//多边形点个数和点数组,凸包存res        sort(p, p + n);        if (n == 0) return 0;        res[0] = p[0];        if (n == 1) return 1;        res[1] = p[1];        if (n == 2) return 2;        res[2] = p[2];        int top=1;        for (int i = 2; i < n; i++) {            while (top && mult(p[i], res[top], res[top-1])) top--;            res[++top] = p[i];        }        int len = top;        res[++top] = p[n - 2];        for (int i = n - 3; i >= 0; i--) {            while (top!=len && mult(p[i], res[top],res[top-1])) top--;            res[++top] = p[i];        }        return top; // 返回凸包中点的个数    }} tu;double caldis(point A,point B) {    return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}double Perimeter() {    double ans = caldis(res[n-1],res[0]);    for(int i=0; i<n-1; i++) {        ans += caldis(res[i],res[i+1]);    }    return ans;}int main() {//    freopen("in.txt","r",stdin);//    freopen("out.txt","w",stdout);    int cas = 0,_;    scanf("%d",&_);    while(_--) {        scanf("%d%d",&n,&d);        for(int i=0; i<n; i++) {            scanf("%lf%lf",&p[i].x,&p[i].y);        }        n = tu.graham(n,p,res);        double c = Perimeter();//        printf("C = %.4f\n",c);        printf("Case #%d: %.4f\n",++cas,c/(PI*d));    }    return 0;}

枚举精度代码:

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#define LL long long#define mt(a,b) memset(a,b,sizeof(a))using namespace std;const double eps = 1e-10;const double PI = acos(-1.0);const double inf = 1e8;struct point {    double x,y;} p[123],res[123];int n,d;bool operator < (const point &l, const point &r) {    return l.y < r.y || (fabs(l.y- r.y)<eps && l.x < r.x);}class ConvexHull { //凸包    bool mult(point sp, point ep, point op) {        return (sp.x - op.x) * (ep.y - op.y)>= (ep.x - op.x) * (sp.y - op.y);    }public:    int graham(int n,point p[],point res[]) {//多边形点个数和点数组,凸包存res        sort(p, p + n);        if (n == 0) return 0;        res[0] = p[0];        if (n == 1) return 1;        res[1] = p[1];        if (n == 2) return 2;        res[2] = p[2];        int top=1;        for (int i = 2; i < n; i++) {            while (top && mult(p[i], res[top], res[top-1])) top--;            res[++top] = p[i];        }        int len = top;        res[++top] = p[n - 2];        for (int i = n - 3; i >= 0; i--) {            while (top!=len && mult(p[i], res[top],res[top-1])) top--;            res[++top] = p[i];        }        return top; // 返回凸包中点的个数    }} tu;double caldis(point A,point B) {    return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));}double Perimeter() {    double ans = caldis(res[n-1],res[0]);    for(int i=0; i<n-1; i++) {        ans += caldis(res[i],res[i+1]);    }    return ans;}struct line {    point a,b;};point intersection(point u1,point u2,point v1,point v2) {    point ret=u1;    double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x)) /((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));    ret.x+=(u2.x-u1.x)*t;    ret.y+=(u2.y-u1.y)*t;    return ret;}point ptoline(point p,line l) {///点到直线上的最近点    point t=p;    t.x+=l.a.y-l.b.y,t.y+=l.b.x-l.a.x;    return intersection(p,t,l.a,l.b);}int main() {//    freopen("in.txt","r",stdin);//    freopen("out.txt","w",stdout);    int cas = 0,_;    scanf("%d",&_);    while(_--) {        scanf("%d%d",&n,&d);        for(int i=0; i<n; i++) {            scanf("%lf%lf",&p[i].x,&p[i].y);        }        n = tu.graham(n,p,res);        ///90度枚举3000次        double zl = 180.0 / 3000;        double l;        double sum = 0.00;        for(double i=0; i<180; i+=zl) {            point S,T;///S为左下点,T为右上点            double cita = i * PI / 180.0;            for(int j=0; j<n; j++) {                point tmp;                double k = tan(cita);                line ll;                ll.a.x = 0.0;                ll.a.y = 0.0;                ll.b.x = 1.0;                ll.b.y = k;                tmp = ptoline(res[j],ll);                if(j==0) {                    S.x =  tmp.x;                    S.y =  tmp.y;                    T.x = tmp.x;                    T.y = tmp.y;                }                S = min(S,tmp);                T = max(T,tmp);            }            l = caldis(S,T);            sum+=l;        }//        printf("sum = %.4f\n",sum);        printf("Case #%d: %.4f\n",++cas,sum/3000/d);    }    return 0;}



0 0