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

题型:计算几何


题意:

       一个平面上有无数个相距为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
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值