bzoj4445&&dtoj#2348. 小凸想跑步(convex)

题目描述:

小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏。

操场是个凸 $n$ 边形,n个顶点按照逆时针从 $0$ ~ $n-1$ 编号。现在小凸随机站在操场的某个位置,标记为 $p$ 点。将 $p$ 点与 $n$ 个顶点各连一条边,形成n个三角形。如果这时 $p$ 点, $0$ 号点, $1$ 号点形成的三角形的面积是 $n$ 个三角形中最小的一个,小凸则认为这是一次正确站位。

现在小凸想知道他一次站位正确的概率是多少。

输入:

第 $1$ 行包含 $1$ 个整数 $n$ ,表示操场的顶点数和游戏的次数。

接下来有 $n$ 行,每行包含 $2$ 个整数 $x_{i},y_{i}$ ,表示顶点的坐标。

输入保证按逆时针顺序输入点,所有点保证构成一个凸多边形。所有点保证不存在三点共线。

算法标签:半平面交

jzy的半平面交初体验=抄代码

思路:

对于站位有两种限制条件,第一种是要在凸多边形内部,第二种对于每一条边建立使得这个点与这条边的构成三角形的面积小于等于这个点与 $0,1$ 号边构成三角形的面积。

用叉积求面积的方法列出三角形面积的式子,可以求得一个不等式。

对于所有的不等式求半平面交,最后在求半平面交围成的面积。

以下代码:

bzoj4445&&dtoj#2348. 小凸想跑步(convex)
#include<bits/stdc++.h>
#define il inline
#define db double
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=2e5+5;
db sum,ans;
int n,tot,q[N],cnt;
struct node{
    db x,y;
    node(){}
    node(db a,db b){x=a;y=b;}
    node operator + (const node &t1) const {return node(x+t1.x,y+t1.y);}
    node operator - (const node &t1) const {return node(x-t1.x,y-t1.y);}
    node operator * (const db &t1) const {return node(x*t1,y*t1);}
}t[N],p[N];
struct line{
    node a,b;
    db k;
    line(){};
    line(node t1,node t2){
        a=t1;b=t2;k=atan2(b.y,b.x);
    }
}l[N];
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
il db cross(node a,node b){
    return a.x*b.y-a.y*b.x;
}
il node P(line a,line b){
    node u=a.a-b.a;
    db tmp=cross(b.b,u)/cross(a.b,b.b);
    return a.a+a.b*tmp;
}
il bool ol(line t1,node t2){
    return cross(t1.b,t2-t1.a)>=0;
}
bool cmp(const line &t1,const line &t2){
    if(fabs(t1.k-t2.k)==0)return ol(t1,t2.a);
    return t1.k<t2.k;
}
il void HPI(){
    sort(l+1,l+1+tot,cmp);
    int j=1;
    for(int i=2;i<=tot;i++)
        if(fabs(l[i].k-l[j].k)>0)l[++j]=l[i];
    tot=j;int h=1,t=2;q[1]=1;q[2]=2;
    for(int i=3;i<=tot;i++){
        while(h<t&&ol(l[i],P(l[q[t-1]],l[q[t]])))t--;
        while(h<t&&ol(l[i],P(l[q[h+1]],l[q[h]])))h++;
        q[++t]=i;
    }
    while(h<t&&ol(l[q[h]],P(l[q[t-1]],l[q[t]])))t--;
    for(int i=h;i<t;i++)p[i]=P(l[q[i]],l[q[i+1]]);
    p[t]=P(l[q[t]],l[q[h]]);
    for(int i=h+1;i<t;i++){
        ans+=cross(p[i]-p[h],p[i+1]-p[h]);
    }
}
int main()
{
    n=read();
    for(int i=0;i<n;i++)t[i].x=read(),t[i].y=read();
    t[n]=t[0];
    for(int i=1;i<n-1;i++)
        sum+=cross(t[i]-t[0],t[i+1]-t[0]);
    for(int i=0;i<n;i++)l[++tot]=line(t[i+1],t[i]-t[i+1]);
    for(int i=1;i<n;i++){
        db a=t[i+1].y-t[i].y-t[1].y+t[0].y;
        db b=t[i+1].x-t[i].x-t[1].x+t[0].x;
        db c=cross(t[i+1],t[i])-cross(t[1],t[0]);
        if(fabs(b)>0)l[++tot]=line(node(0,c/b),node(-b,-a));
        else if(fabs(a)>0)l[++tot]=line(node(-c/a,0),node(0,-a));
    }
    HPI();
    printf("%.4lf\n",ans/sum);
    return 0;
}
View Code

 

上一篇:前端绘制聚合的区域范围


下一篇:HTML系列之预格式化文本pre标签