【计算几何】【凸包】Atcoder 3868 Holes

题意:

在一个平面坐标系中,有一个半径为R的圆 R=10101010 ( R = 10 10 10 10 ) ,其圆心在原点处。给出平面上N个点(N≤100),现在随机得到一个圆内的点,它会选择与它距离最近的一个点,(如果同时有多个,选择编号最小的一个),现在求给出的N个点中,每个点被选中的概率。
给出的点的坐标(x,y)满足 |x|,|y|106 | x | , | y | ≤ 10 6


分析:

如果对极限的思想有一定的理解,那么这道题就变得非常非常水了,考虑到R极大,与给出点的坐标范围相比,就可以近似地看作是无限大。
这样一来,我们考虑求出给出点的凸包,凸包内部的面积相对于外部的无限大来说,可以忽略不计,所以我们可以忽略随机到凸包内部某点的情况。
这里写图片描述
我们发现,白色区域的面积相对于其他的面积来说,在极限的思想下,是可以忽略不计的,而当点位于同一种颜色时,总会选择同一个点(即区域前的字母)。这个区域的两条边分别于其相邻的,凸包上的边垂直。
在极限的思想下,要比较这几个区域的面积,我们只需要比较,凸包上某点与其对应区域所形成的角的大小。所以求出凸包后,在凸包上遍历一遍:
对凸包上的每个点,求出其相邻的两边的点积 A⃗ B⃗ =|A||B|cos<A⃗ ,B⃗ > ( A → ⋅ B → = | A | ⋅ | B | ⋅ cos < A → , B → > )
将这个值除以两边长,再取其相反数,即为我们要求的角的cos值,再用系统函数中的acos,就可以求出比例了。
(注意,这道题有点卡精度)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 110
#define EPS 1e-7
using namespace std;
const double Pi=acos(-1);
struct node{
    double x,y;
    int id;
    node(){}
    node(double xx,double yy):x(xx),y(yy) {}
    node operator + (const node &a) const {
        return node(x+a.x,y+a.y);
    }
    node operator - (const node &a) const {
        return node(x-a.x,y-a.y);
    }
    node operator * (const double &t) const {
        return node(x*t,y*t);
    }
    double operator *(const node &a) const{
        return x*a.x+y*a.y;
    }
    double operator ^(const node &a) const{
        return x*a.y-y*a.x;
    }
    bool operator <(const node &a) const {
        return fabs(y-a.y)<EPS?x<a.x:y<a.y;
    }
}p[MAXN],l1[MAXN];
stack<node> s1,s;
double ans[MAXN];
int n,cnt1;
void solve(node a1[],int &cnt){
    s.push(p[1]);
    s1.push(p[1]);
    s1.push(p[2]);
    for(int i=3;i<=n;i++){
        while(!s.empty()&&((p[i]-s.top())^(s1.top()-s.top()))<-EPS){
            s.pop();
            s1.pop();
        }
        s.push(s1.top());
        s1.push(p[i]);
    }
    while(!s1.empty()){
        a1[++cnt]=s1.top();
        s1.pop();
    }
    while(!s.empty())
        s.pop();
}
bool cmp(node a,node b){
    return b<a;
}
double len(node a){
    return sqrt(a.x*a.x+a.y*a.y);
}
pair<long long,long long> b[MAXN];
bool check(){
    for(int i=1;i<=n;i++){
        b[i].first=(long long)(p[i].x);
        b[i].second=(long long)(p[i].y);
    }
    for(int i=2;i<n;i++){
        long long xx1=b[i].first-b[i-1].first;
        long long xx2=b[i+1].first-b[i].first;
        long long yy1=b[i].second-b[i-1].second;
        long long yy2=b[i+1].second-b[i].second;
        if(yy1*xx2!=yy2*xx1)
            return 0;
    }
    return 1;
}
int main(){
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    SF("%d",&n);
    for(int i=1;i<=n;i++){
        SF("%lf%lf",&p[i].x,&p[i].y);
        p[i].id=i;
    }
    sort(p+1,p+1+n);
    if(n==2){
        PF("0.50000\n");
        for(int i=2;i<n;i++)
            PF("0.00000\n");
        PF("0.50000\n");
        return 0;
    }
    solve(l1,cnt1);
    sort(p+1,p+1+n,cmp);
    cnt1--;
    solve(l1,cnt1);
    cnt1--;
    for(int i=1;i<=cnt1;i++){
        int las,nxt;
        if(i==1)
            las=cnt1;
        else
            las=i-1;
        if(i==cnt1)
            nxt=1;
        else
            nxt=i+1;
        double d=((l1[nxt]-l1[i])*(l1[las]-l1[i]))/(len(l1[nxt]-l1[i])*len(l1[las]-l1[i]));
        //PF("[%lf]",fabs((l1[nxt]-l1[i])*(l1[i]-l1[las])));
        d=acos(-d);
        ans[l1[i].id]=d/(2.0*Pi);
    }
    for(int i=1;i<=n;i++)
        PF("%.20lf\n",ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值