Description
- 题目给你一个凸多边形,可以绕原点随便转,剪刀固定方向,限制长度,求可以剪开的概率
Solution
- 这是一种巧妙的
暴力做法 - 转多边形很麻烦,我们相对地想到转剪刀方向
- 我们每次把剪刀转一点点
- “一点点”来自精度要求
1
0
−
4
10^{-4}
10−4,
2
π
3
∗
1
0
5
r
a
d
\cfrac{2\pi}{3*10^5}\,\,rad
3∗1052πrad绰绰有余
- 算出剪刀沿此方向需要剪的距离,与
L
L
L比较
- 如果超过
L
L
L说明剪不开
#include <bits/stdc++.h>
const int N=1e5+10;
const double P=acos(0.0)*2.0,eps=1e-8;
using namespace std;
int n;double d,L;
int sgn(double x){return (fabs(x)<eps)?0:(x<0?-1:1);}
struct Point{
double x,y;
Point(){}
Point(double _x,double _y){x=_x,y=_y;}
Point operator +(Point a){return Point(x+a.x,y+a.y);}
Point operator -(Point a){return Point(x-a.x,y-a.y);}
double operator *(Point a){return x*a.x+y*a.y;}
Point operator %(double a){return Point(x*a,y*a);}
double operator ^(Point a){return x*a.y-y*a.x;}
}v[N<<2];
struct Line{Point s,e;Line(){}Line(Point _s,Point _e){s=_s,e=_e;}}ln;
Point rotate(Point c,double a){return Point(c.x*cos(a)-c.y*sin(a),c.x*sin(a)+c.y*cos(a));}
Point LIL(Line a,Line b){return a.s+(a.e-a.s)%(((b.e-b.s)^(b.s-a.s))/((b.e-b.s)^(a.e-a.s)));}
double displ(Point a,Line b){
Point v1=b.e-b.s,v2=a-b.s;
return fabs(v1^v2)/sqrt(v1.x*v1.x+v1.y*v1.y);
}int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf",&v[i].x,&v[i].y),v[i+n]=v[i],v[i+2*n]=v[i],v[i+3*n]=v[i];
scanf("%lf%lf%lf%lf%lf",&L,&ln.s.x,&ln.s.y,&ln.e.x,&ln.e.y);
d=displ(Point(0,0),ln);
Point p0(0.0,0.0);
int cnt=0,tot=3e5,l=1,r=1;
for(int i=0;i<tot;++i){
double a=i*2*P/tot;
Point cur=Point(cos(a),sin(a))%d;
Point vv=rotate(cur,P/2);
Point nxt=cur+vv;
Point p1,p2;
Line s0=Line(cur,nxt);
while(true){
int o1=sgn((nxt-cur)^(v[l]-nxt));
int o2=sgn((nxt-cur)^(v[l+1]-nxt));
if(o1*o2==1){++l;continue;}
p1=LIL(s0,Line(v[l],v[l+1]));
break;
}r=max(r,l+1);
while(true){
int o1=sgn((nxt-cur)^(v[r]-nxt));
int o2=sgn((nxt-cur)^(v[r+1]-nxt));
if(o1*o2==1){++r;continue;}
p2=LIL(s0,Line(v[r],v[r+1]));
break;
}Point p=p1-p2;
double res=sqrt(p.x*p.x+p.y*p.y);
if(sgn(L-res)<0) ++cnt;
}printf("%.4lf\n",1.0*cnt/tot);
}