原题链接
参考资料
解题思路
随着圆的半径增大,能看到的面积单调不降,所以可以二分寻找满足条件的最小半径。
将多边形的每个顶点与原点连接,构成多个三角形。每个三角形都有一个对应圆心角的扇形。
通过分类讨论每个三角形与其对应扇形的交集面积,可以计算出能看到的面积。
函数定义
f1(A,B)
f1(A,B):表示三角形 △OAB 的有向面积。
通过向量叉积计算 f1:
f1(A,B)=2OA×OB
double f1(Point A,Point B)
{
return Cross(A,B)/2;
}
f2(A,B,r)
f2(A,B,r):表示由 OA 和 OB 两条边围成且半径为 r 的扇形的有向面积。
通过向量的叉积和点积计算出扇形的圆心角 θ=∠AOB:
θ=arctan(cos∠AOBsin∠AOB)=atan2(OA×OB,OA⋅OB)
根据扇形面积公式计算 f2:
f2(A,B,r)=2θ⋅r2=2atan2(OA×OB,OA⋅OB)⋅r2
double f2(Point A,Point B,double r)
{
return atan2(Cross(A,B),Dot(A,B))*r*r/2;
}
calc(A,B,r)
calc(A,B,r):表示每个三角形与其对应扇形的交集面积。
接下来通过分类讨论计算 calc,设:
S=calc(A,B,r)
分类讨论
Case #1
如果点 A,B 距离圆心的距离都小于 r:
∣OA∣≤r∧∣OB∣≤r
此时扇形完全包含三角形,面积交集就是三角形的面积:
S=f1(A,B)
if(Len(A)<=r&&Len(B)<=r)return f1(A,B);
判断相交
接下来我们需要判断直线 AB 是否与圆有交点 P。
直线 AB 的参数方程:
OP=OA+t⋅AB
代入圆的方程:
r=∣OP∣=∣OA+t⋅AB∣
整理为标准二次方程:
at2+bt+c=0
计算方程的系数:
a=∣AB∣2,b=2⋅OA⋅AB,c=∣OA∣2−r2
double a=Len2(B-A),b=Dot(A,B-A)*2,c=Len2(A)-r*r;
计算判别式 Δ:
Δ=b2−4ac
Case #2
如果直线与圆没有交点或相切:
Δ≤0
此时三角形完全包含扇形,面积交集就是扇形的面积:
S=f2(A,B,r)
if(d<=0)return f2(A,B,r);
计算交点
接下来通过求根公式,计算出 t:
t1=2a−b−Δ,t2=2a−b+Δ
double t1=(-b-sqrt(d))/(a*2),t2=(-b+sqrt(d))/(a*2);
代入直线方程,计算出直线与圆的交点 P:
OP=OA+t⋅AB
我们令距离 A 较近的交点为 C,距离 B 较近的交点为 D:
OC=OA+t1⋅AB,OD=OA+t2⋅AB
Point C=A+(B-A)*t1,D=A+(B-A)*t2;
Case #3
如果点 C,D 都在点 A,B 的同一侧(即线段 AB 的延长线上):
t1≥1∨t2≤0
此时三角形也完全包含扇形,面积交集就是扇形的面积:
S=f2(A,B,r)
if(t1>=1||t2<=0)return f2(A,B,r);
Case #4
如果点 D 在线段 AB 上:
t1≤0
此时 AD 是三角形面积,DB 是扇形面积:
S=f1(A,D)+f2(D,B,r)
if(t1<=0)return f1(A,D)+f2(D,B,r);
Case #5
如果点 C 在线段 AB 上:
t2≥1
此时 AC 是扇形面积,CB 是三角形面积:
S=f2(A,C,r)+f1(D,B)
if(t2>=1)return f2(A,C,r)+f1(C,B);
Case #6
否则点 C,D 都在线段 AB 上。
此时 AC 是扇形面积,CD 是三角形面积,DB 是扇形面积:
S=f2(A,C,r)+f1(C,D)+f2(D,B,r)
return f2(A,C,r)+f1(C,D)+f2(D,B,r);
参考代码