小凸想跑步

小凸想跑步

时间限制: 1 Sec 内存限制: 128 MB

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

输入
第1行包含1个整数n,表示操场的顶点数和游戏的次数。
接下来有n行,每行包含2个整数xi,yi,表示顶点的坐标。
输入保证按逆时针顺序输入点,所有点保证构成一个凸多边形。所有点保证不存在三点共线。

输出
输出1个数,正确站位的概率,保留4个小数。

样例输入
5
1 8
0 7
0 0
8 0
8 8

样例输出
0.6316

数据范围
对于30%的数据,3≤n≤4,0≤x,y≤10
对于100%的数据,3≤n≤105,-109≤x,y≤109

来源
SCOI 2015 Day1

题解

对于每一条边,我们可以解一个不等式得到以它为底的三角形面积大于以01号点连边为底的三角形的范围,由此可以得到N个半平面,然后求半平面角即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define N 100010
#define eps 1e-7
using namespace std;
int n,tot;
double ans1,ans2;
struct point{
  double x,y;
  point operator+(const point &p)
  const{return (point){x+p.x,y+p.y};}
  point operator-(const point &p)
  const{return (point){x-p.x,y-p.y};}
  point operator*(const double &num)
  const{return (point){x*num,y*num};}
  double operator^(const point &p)
  const{return x*p.y-p.x*y;}
}t[N],p[N*2];
struct node{
  point p,v;double ang;
  bool operator<(const node &x)
  const{return ang<x.ang||(ang==x.ang&&(v^(x.p-p))<eps);}
}s[N*2],q[N*2];
bool pd(node a,point b){return (a.v^(b-a.p))<-eps;}
double get_ang(point p){return atan2(p.y,p.x);}
point get_jd(node a,node b)
{
  point x=a.p-b.p;
  double t=(b.v^x)/(a.v^b.v);
  return a.p+a.v*t;
}

void solve()
{
  sort(s+1,s+n+1);tot=1;
  for(int i=2;i<=n;i++)
    if(fabs(s[i].ang-s[i-1].ang)>eps)s[++tot]=s[i];
  int l=1,r=2;q[1]=s[1];q[2]=s[2];n=tot;
  for(int i=3;i<=n;i++)
  {
    while(l<r&&pd(s[i],get_jd(q[r],q[r-1])))r--;
    while(l<r&&pd(s[i],get_jd(q[l],q[l+1])))l++;
    q[++r]=s[i];
  }
  while(l<r&&pd(q[l],get_jd(q[r],q[r-1])))r--;
  while(l<r&&pd(q[r],get_jd(q[l],q[l+1])))l++;
  if(r-l<=1)return;
  q[r+1]=q[l];tot=0;
  for(int i=l;i<=r;i++)p[++tot]=get_jd(q[i],q[i+1]);
  p[tot+1]=p[1];
  for(int i=1;i<=tot;i++)ans2+=fabs((p[i]-p[1])^(p[i+1]-p[1]));
}

void prepare()
{
  double X1=t[1].x,Y1=t[1].y;
  double X2=t[2].x,Y2=t[2].y;
  for(int i=2;i<=n;i++)
  {
    double X3=t[i].x,Y3=t[i].y;
    double X4=t[i+1].x,Y4=t[i+1].y;
    double a=Y1-Y2-Y3+Y4,b=X2-X1-X4+X3;
    double c=X3*Y4-X4*Y3+X2*Y1-X1*Y2;
    double p1,p2,p3,p4;
    if(fabs(a)<eps){p1=0,p2=c/b,p3=1,p4=c/b;if(b>0)swap(p1,p3),swap(p2,p4);}
    else if(fabs(b)<eps){p1=c/a,p2=0,p3=c/a,p4=1;if(a<0)swap(p1,p3),swap(p2,p4);}
         else if(b<0)p1=0,p2=c/b,p3=1,p4=c/b-a/b;
              else p1=1,p2=c/b-a/b,p3=0,p4=c/b;
    point X1=(point){p1,p2},X2=(point){p3-p1,p4-p2};
    s[i]=(node){X1,X2,get_ang(X2)};
  }
  s[1]=(node){t[1],t[2]-t[1],get_ang(t[2]-t[1])};
} 

int main()
{
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
    scanf("%lf%lf",&t[i].x,&t[i].y);t[n+1]=t[1];
  for(int i=1;i<=n;i++)ans1+=((t[i]-t[1])^(t[i+1]-t[1]));
  prepare();solve();
  printf("%.4lf",ans2/ans1);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值