HDU 4978 A simple probability problem.(思维+凸包)

探讨了一个关于无限平面上硬币随机投掷后线段与平面直线相交概率的问题,利用凸包算法进行计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博客原文地址:http://blog.youkuaiyun.com/xuechelingxiao/article/details/38827629


A simple probability problem.


多校第十场的一道几何,做了好久了,忘了发出来。比赛的时候由于坑爹的模板,后台100组数据错了一组,导致比赛的时候没做出来,赛后郁闷了好久。。。。。比赛之后好好整了一下凸包的模板,代码里会是Graham算法,标程用的是Andrew算法。


题目大意:一个无限大的平面上,有间距为D的无限条水平直线,如图所示。

给你一个直径为D的硬币,硬币中有n个点,每两个点之间都有一条线段,任意三点不会共线。随机的将硬币扔到上图中的平面内,问至少有一条线段跟平面内的直线相交的概率是多少。


解题思路:很容易想到的是,对于硬币上的所有点来说,无疑是构成一个凸包的时候为所求的情况,而当点的个数为1的时候,概率为0。


#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
const double eps = 1e-6;
const double Pi = acos(-1.0);
#define zero(x) (((x) > 0 ? (x) : (-x)) < eps)

int q, n;

struct Point
{
    double x,y;
    Point() {}  Point(double _x,double _y)
    {
        x = _x;
        y = _y;
    }  Point operator -(const Point &b)const
    {
        return Point(x - b.x,y - b.y);
    }  //叉积
    double operator ^(const Point &b)const
    {
        return x*b.y - y*b.x;     //点积
    }
    double operator *(const Point &b)const
    {
        return x*b.x + y*b.y;     //绕原点旋转角度B(弧度值),后x,y的变化
    }
    void transXY(double B)
    {
        double tx = x,ty = y;
        x = tx*cos(B) - ty*sin(B);
        y = tx*sin(B) + ty*cos(B);
    }
} P[105], ch[105];

double Distance(Point a, Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double xmult(Point p1, Point p2, Point p){
    return (p1.x-p.x)*(p2.y-p.y) - (p1.y-p.y)*(p2.x-p.x);
}
int dcmp(double x){
    return fabs(x)<eps?0:(x<0?-1:1);
}
bool cmp(Point a, Point b){
    if(dcmp(xmult(a, b, P[0])) == 0){
        return Distance(a, P[0]) < Distance(b, P[0]);
    }
    else {
        return dcmp(xmult(a, b, P[0])) > 0;
    }
}
int Graham(int n){
    int s = 0, top = 1;
    for(int i = 0; i < n; ++i){
        if(P[i].y < P[s].y || (P[i].y == P[s].y && P[i].x < P[s].x)){
            s = i;
        }
    }
    if(s != 0){
        Point tmp = P[0];
        P[0] = P[s];
        P[s] = tmp;
    }
    sort(P+1, P+n, cmp);
    ch[0] = P[0], ch[1] = P[1];
    for(int i = 2; i < n; ++i){
        while(top > 0 && dcmp(xmult(ch[top], P[i], ch[top-1])) < 0){
            top--;
        }
        ch[++top] = P[i];
    }
    return top+1;
}


int T;
double d;

int main()
{
    //freopen("1008.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    int icase = 1;
    scanf("%d", &T);
    while(T--){
        scanf("%d%lf", &n, &d);
        for(int i = 0; i < n; ++i){
            scanf("%lf%lf", &P[i].x, &P[i].y);
        }
        printf("Case #%d: ", icase++);
        if(n >= 3){
            int t = Graham(n);
            //printf("%d\n", t);
            double sum = Distance(ch[0], ch[t-1]);
            for(int i = 0; i < t-1; ++i){
                sum += Distance(ch[i], ch[i+1]);
            }
            //printf("q = %d\n", q);
            //printf("%lf\n", Area());
            //printf("%lf\n" ,sum);
            printf("%.4lf\n", sum/(Pi*(d)));
        }
        else if(n == 2){
            double dis = Distance(P[0], P[1]);
            printf("%.4lf\n", 2*dis/(Pi*d));
        }
        else {
            printf("0.0000\n");
        }
        //printf("%lf %lf\n", Min.y, Max.y);
    }

    return 0;
}

/*
100
3 3
0 1
1 0
-1 0
*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值