题意
小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏。
操场是个凸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;
}