bzoj 4445: [Scoi2015]小凸想跑步

题意

小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏。
操场是个凸n边形,N个顶点按照逆时针从0~n-l编号。现在小凸随机站在操场中的某个位置,标记为P点。将P点与n个顶点各连一条边,形成N个三角形。如果这时P点,0号点,1号点形成的三角形的面积是N个三角形中最小的一个,小凸则认为这是一次正确站位。
现在小凸想知道他一次站位正确的概率是多少。

题解

第一个半平面交的应用。。
TKJ教我的
我们考虑,如果我们设这个点为 (x,y) ( x , y )
那么我们用n个三角形的条件可以列出n个不等式
也就是类似于 ax+by<=c a x + b y <= c 的不不等式
这个对于b进行分类讨论,可以化成若干个半平面
然后求半平面交就可以了
最后用半平面交的面积比上重面积就是我们要求的
最后有TKJ的一个强制四舍五入才过
CODE:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef double LB;
const int N=(1e5+5)*3;
const LB eps=1e-15;
struct pnt{LB x,y;}a[N];
struct qq
{
    pnt x,y;
    LB angle;
}s[N];int tot=0;
int n;
void add (LB x1,LB y1,LB x2,LB y2)
{
    tot++;
    s[tot].x={x1,y1};
    s[tot].y={x2,y2};
    s[tot].angle=atan2(y2-y1,x2-x1);
}
void ins (LB a,LB b,LB c)//ax+by<=c
{
//  printf("OZY:%lf %lf %lf\n",a,b,c);
    if (abs(b)<eps)
    {
        if (a>eps) add(c/a,0,c/a,1);
        else add(c/a,1,c/a,0);
        return ;
    }
    pnt p1={0,c/b},p2={1,(c-a)/b};
    if (b>eps)
        add(p2.x,p2.y,p1.x,p1.y);
    else
        add(p1.x,p1.y,p2.x,p2.y);
}
LB mul (pnt x,pnt y,pnt z)
{
    LB x1=x.x-z.x,y1=x.y-z.y;
    LB x2=y.x-z.x,y2=y.y-z.y;
    return x1*y2-x2*y1;
}
bool cmp (qq x,qq y)
{
    if (abs(x.angle-y.angle)<eps)
        return mul(x.x,x.y,y.x)<-eps;
    return x.angle<y.angle;
}
int q[N];
pnt JD (qq x,qq y)//求两直线的交点 
{
    LB s1=mul(x.y,y.x,x.x);
    LB s2=mul(y.y,x.y,x.x);
    pnt xx;
    xx.x=(y.x.x*s2+y.y.x*s1)/(s1+s2);
    xx.y=(y.x.y*s2+y.y.y*s1)/(s1+s2);
    return xx;
}
bool check (qq x,qq a,qq b)
{
    pnt xx=JD(a,b);
    return mul(x.y,xx,x.x)<-eps;
}
pnt ans[N];
int nn;
void solve ()
{
    sort(s+1,s+1+tot,cmp);
    //  for (int u=1;u<=tot;u++) printf("%.0lf %.0lf %.0lf %.0lf %.0lf\n",s[u].x.x,s[u].x.y,s[u].y.x,s[u].y.y,s[u].angle);
    nn=1;
    for (int u=2;u<=tot;u++)
        if (s[u].angle-s[nn].angle>eps)
            s[++nn]=s[u];
    tot=nn;
    int st=1,ed=2;
    q[1]=1;q[2]=2;
    for (int u=3;u<=tot;u++)
    {
        while (st<ed&&check(s[u],s[q[ed]],s[q[ed-1]])) ed--;
        while (st<ed&&check(s[u],s[q[st]],s[q[st+1]])) st++;
        q[++ed]=u;
    }

    while (st<ed&&check(s[q[st]],s[q[ed]],s[q[ed-1]])) ed--;
    while (st<ed&&check(s[q[ed]],s[q[st]],s[q[st+1]])) st++;
    q[++ed]=q[st];
    nn=0;
    for (int u=st;u<ed;u++)  ans[++nn]=JD(s[q[u]],s[q[u+1]]);
}
int main()
{
    scanf("%d",&n);
    LB sum=0;
    for (int u=1;u<=n;u++)
        scanf("%lf%lf",&a[u].x,&a[u].y);
    for (int u=3;u<=n;u++)   sum=sum+mul(a[u],a[u-1],a[1]);
    for (int u=2;u<=n;u++)   add(a[u-1].x,a[u-1].y,a[u].x,a[u].y);
    add(a[n].x,a[n].y,a[1].x,a[1].y);
    for (int u=2;u<=n;u++)//这条线段和第一个所形成的 
    {
        qq x=s[1],y=s[u];
        ins(x.x.y-x.y.y-y.x.y+y.y.y,
        x.y.x-x.x.x+y.x.x-y.y.x,
        x.x.y*(x.y.x-x.x.x)-x.x.x*(x.y.y-x.x.y)-y.x.y*(y.y.x-y.x.x)+y.x.x*(y.y.y-y.x.y));
    }
    solve();
    if (nn<=2) {printf("0.0000\n");return 0;}
    /*for (int u=1;u<=nn;u++)
        printf("TYB:%lf %lf\n",ans[u].x,ans[u].y);*/
    LB lalal=0;
//  for (int u=1;u<=n;u++) printf("%Lf %Lf\n",ans[u].x,ans[u].y); 
    for (int u=3;u<=nn;u++)  lalal=lalal+mul(ans[u],ans[u-1],ans[1]);
//  printf("%.4lf %Lf\n",lalal,sum);
   char ss[10];
    //printf("%lf\n",ans);
    sprintf(ss,"%.6lf",lalal/sum);
    if(ss[6]>='5')
    {
        ss[5]++;
        if(ss[5]>'9')
        {
            ss[5]='0';
            ss[4]++;
        }
        if(ss[4]>'9')
        {
            ss[4]='0';
            ss[3]++;
        }
        if(ss[3]>'9')
        {
            ss[3]='0';
            ss[2]++;
        }
        if(ss[2]>'9')
        {
            ss[2]='0';
            ss[0]++;
        }
    }
    for(int i=0;i<6;i++)
    printf("%c",ss[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值