题面描述
思路
先看一下SCY的视频吧,讲得真的很清(luo)楚(suo)。
忽略掉一些奇奇怪怪的语言
首先我们先来了解一下SCY开头说的 a x + b y + c = 0 ax+by+c=0 ax+by+c=0
也就是下面这条直线?
我稍微纳闷了一会,这不是
y
=
k
x
+
b
y=kx+b
y=kx+b吗?
稍微转换一下?
a x + b y + c = 0 ax+by+c=0 ax+by+c=0
b y = − a x − c by=-ax-c by=−ax−c
y = − a b x − c b y=-\frac{a}{b}x-\frac{c}{b} y=−bax−bc
这不就出来了吗。
这个东西我们以后会用到的。
a t a n atan atan函数就是已知边长,逆向求近似度数的一个玄学函数。
就如下图:
设 t a n θ = 3.49 − 7.99 , a t a n ( 3.49 , − 7.99 ) = θ tan\theta=\frac{3.49}{-7.99},atan(3.49,-7.99)=\theta tanθ=−7.993.49,atan(3.49,−7.99)=θ
特别地, θ \theta θ是弧度制
void get_angle(){angle=atan2(p2.y-p1.y,p2.x-p1.x);}
这句话实际上的意思就为将这条有向的线段当作向量(其实就是向量),将起点挪到原点处,求出它的 a t a n atan atan值。
之后我们用 a t a n atan atan来排序
bool cmp(segment sg1,segment sg2)
{
if(sg1.angle<sg2.angle)return true;
}
这个排序实际上是将线段(直线)的方向有序化了,大概是这样一个形状(此处是已经经过挪移的形状):
此处按字典序小的排在前面为排序后的结果。
那么有一些特殊的情况,
比如
两条带方向的直线平行(图中仅给出线段,因为可以从线段中推出直线):
注意这里的平行实际意义上为
s
g
1.
a
n
g
l
e
=
=
a
g
2.
a
n
g
l
e
sg1.angle==ag2.angle
sg1.angle==ag2.angle。
此时我们应该选择 p 1 p_1 p1还是 p 2 p_2 p2呢,
选择 p 1 p_1 p1,因为 p 2 箭 头 半 平 面 ∪ p 1 箭 头 左 边 的 半 平 面 = p 1 箭 头 左 边 的 半 平 面 p_2箭头半平面\cup p_1箭头左边的半平面=p_1箭头左边的半平面 p2箭头半平面∪p1箭头左边的半平面=p1箭头左边的半平面
我们要求是半平面的交集。
fabs(sg1.angle-sg2.angle)<eps
判断是否平行
pd(sg1.p1,sg2)
判断
s
g
1
sg1
sg1是否在
s
g
2
sg2
sg2左面
那么现在 p 1 p_1 p1的位置先于 p 2 p_2 p2的位置。
完整的cmp
bool cmp(segment sg1,segment sg2)
{
if(sg1.angle<sg2.angle)return true;
if(fabs(sg1.angle-sg2.angle)<eps&&pd(sg1.p1,sg2))return true;
return false;
}
接下来就 p d pd pd函数:
bool pd(point p,segment sg)//是否在此直线左侧
{
if(mul(p,sg.p2,sg.p1)<=eps)return true;//叉乘之积为负数即为左侧
return false;
}
个人认为 j d jd jd是通篇最难的一个函数了。
先讲讲被SCY蓝掉的那个 j d jd jd吧
因为:
它要推柿子
我们要用到上面的结论直线 a x + b y + c = 0 ax+by+c=0 ax+by+c=0。
首先我们要解一个解析式方程组求半平面交点
{ a 1 x + b 1 y + c 1 = 0 a 2 x + b 2 y + c 2 = 0 \begin{cases}a_1x+b_1y+c_1=0\\a_2x+b_2y+c_2=0\end{cases} {a1x+b1y+c1=0a2x+b2y+c2=0
我们要求的是 x , y x,y x,y,
首先我们看看怎么求一组 ( a 1 , b 1 , c 1 ) (a_1,b_1,c_1) (a1,b1,c1)吧。
首先 p 1 , p 2 p_1,p_2 p1,p2点在 a 1 x + b 1 y + c 1 = 0 a_1x+b_1y+c_1=0 a1x+b1y+c1=0这条直线上了。
故 { a 1 p 1 . x + b 1 p 1 . y + c 1 = 0 ⋯ ① a 1 p 2 . x + b 1 p 2 . y + c 1 = 0 ⋯ ② \begin{cases}a_1p_1.x+b_1p_1.y+c_1=0\cdots ①\\a_1p_2.x+b_1p_2.y+c_1=0\cdots②\end{cases} {a1p1.x+b1p1.y+c1=0⋯①a1p2.x+b1p2.y+c1=0⋯②
①式-②式,得 a 1 ( p 1 . x − p 2 . x ) + b 1 ( p 1 . y − p 2 . y ) = 0 a_1(p_1.x-p_2.x)+b_1(p_1.y-p_2.y)=0 a1(p1.x−p2.x)+b1(p1.y−p2.y)=0
发现这是一个不定方程。
求特解
解得: a 1 = p 1 . y − p 2 . y , b 1 = p 2 . x − p 1 . x a_1=p_1.y-p_2.y,b_1=p_2.x-p_1.x a1=p1.y−p2.y,b1=p2.x−p1.x
正好满足。
将 a 1 , b 1 a_1,b_1 a1,b1代入①式就有:
p 1 . x ∗ p 1 . y − p 1 . x ∗ p 2 . y + p 2 . x ∗ p 1 . y − p 1 . x ∗ p 1 . y + c 1 = 0 p_1.x*p_1.y-p_1.x*p_2.y+p_2.x*p_1.y-p_1.x*p_1.y+c_1=0 p1.x∗p1.y−p1.x∗p2.y+p2.x∗p1.y−p1.x∗p1.y+c1=0
p 2 . x ∗ p 1 . y − p 1. x ∗ p 2 . y + c 1 = 0 p_2.x*p_1.y-p1.x*p_2.y+c_1=0 p2.x∗p1.y−p1.x∗p2.y+c1=0
c 1 = p 1 . x ∗ p 2 . y − p 2 . x ∗ p 1 . y c_1=p_1.x*p_2.y-p_2.x*p_1.y c1=p1.x∗p2.y−p2.x∗p1.y
a 2 , b 2 , c 2 a_2,b_2,c_2 a2,b2,c2同理可得。
a 2 = p 3 . y − p 4 . y , b 2 = p 4 . x − p 3 . x , c 2 = p 3 . x ∗ p 4 . y − p 4 . x ∗ p 3 . y a_2=p_3.y-p_4.y,b_2=p_4.x-p_3.x,c_2=p_3.x*p_4.y-p_4.x*p_3.y a2=p3.y−p4.y,b2=p4.x−p3.x,c2=p3.x∗p4.y−p4.x∗p3.y
之后就是解方程了
{ a 1 x + b 1 y + c 1 = 0 a 2 x + b 2 y + c 2 = 0 \begin{cases}a_1x+b_1y+c_1=0\\a_2x+b_2y+c_2=0\end{cases} {a1x+b1y+c1=0a2x+b2y+c2=0
{ a 1 x + b 1 y = − c 1 a 2 x + b 2 y = − c 2 \begin{cases}a_1x+b_1y=-c_1\\a_2x+b_2y=-c_2\end{cases} {a1x+b1y=−c1a2x+b2y=−c2
{ a 1 x = − c 1 − b 1 y a 2 x = − c 2 − b 2 y \begin{cases}a_1x=-c_1-b_1y\\a_2x=-c_2-b_2y\end{cases} {a1x=−c1−b1ya2x=−c2−b2y
{ x = − c 1 + b 1 ∗ y a 1 x = − c 2 + b 2 ∗ y a 2 \begin{cases}x=-\frac{c_1+b_1*y}{a_1}\\x=-\frac{c_2+b_2*y}{a_2}\end{cases} {x=−a1c1+b1∗yx=−a2c2+b2∗y
c 1 + b 1 ∗ y a 1 = c 2 + b 2 ∗ y a 2 \frac{c_1+b_1*y}{a_1}=\frac{c_2+b_2*y}{a_2} a1c1+b1∗y=a2c2+b2∗y
( c 1 + b 1 ∗ y ) ∗ a 2 = ( c 2 + b 2 ∗ y ) ∗ a 1 (c_1+b_1*y)*a_2=(c_2+b_2*y)*a_1 (c1+b1∗y)∗a2=(c2+b2∗y)∗a1
c 1 ∗ a 2 + a 2 ∗ b 1 ∗ y = c 2 ∗ a 1 + a 1 ∗ b 2 ∗ y c_1*a_2+a_2*b_1*y=c_2*a_1+a_1*b_2*y c1∗a2+a2∗b1∗y=c2∗a1+a1∗b2∗y
( a 2 ∗ b 1 − a 1 ∗ b 2 ) y = c 2 ∗ a 1 − c 1 ∗ a 2 (a_2*b_1-a_1*b_2)y=c_2*a_1-c_1*a_2 (a2∗b1−a1∗b2)y=c2∗a1−c1∗a2
y = c 2 ∗ a 1 − c 1 ∗ a 2 a 2 ∗ b 1 − a 1 ∗ b 2 y=\frac{c_2*a_1-c_1*a_2}{a_2*b_1-a_1*b_2} y=a2∗b1−a1∗b2c2∗a1−c1∗a2
同理
x = c 1 ∗ b 2 − c 2 ∗ b 1 a 2 ∗ b 1 − a 1 ∗ b 2 x=\frac{c_1*b_2-c_2*b_1}{a_2*b_1-a_1*b_2} x=a2∗b1−a1∗b2c1∗b2−c2∗b1
终于写完一个了。
SCY标程中的那个其实是更加简化的一个东西:
x = c 1 ∗ b 2 − c 2 ∗ b 1 a 2 ∗ b 1 − a 1 ∗ b 2 = ( p 1 . x ∗ p 2 . y − p 2 . x ∗ p 1 . y ) ∗ ( p 4 . x − p 3 . x ) − ( p 3 . x ∗ p 4 . y − p 4 . x ∗ p 3 . y ) ∗ ( p 2 . x − p 1 . x ) ( p 3 . y − p 4 . y ) ∗ ( p 2 . x − p 1 . x ) − ( p 1 . y − p 2 . y ) ∗ ( p 4 . x − p 3 . x ) x=\frac{c_1*b_2-c_2*b_1}{a_2*b_1-a_1*b_2}=\frac{(p_1.x*p_2.y-p_2.x*p_1.y)*(p_4.x-p_3.x)-(p_3.x*p_4.y-p_4.x*p_3.y)*(p_2.x-p_1.x)}{(p_3.y-p_4.y)*(p_2.x-p_1.x)-(p_1.y-p_2.y)*(p_4.x-p_3.x)} x=a2∗b1−a1∗b2c1∗b2−c2∗b1=(p3.y−p4.y)∗(p2.x−p1.x)−(p1.y−p2.y)∗(p4.x−p3.x)(p1.x∗p2.y−p2.x∗p1.y)∗(p4.x−p3.x)−(p3.x∗p4.y−p4.x∗p3.y)∗(p2.x−p1.x)
= ( p 1 . x ∗ p 2 . y − p 2 . x ∗ p 1 . y ) ∗ ( p 4 . x − p 3 . x ) − ( p 3 . x ∗ p 4 . y − p 4 . x ∗ p 3 . y ) ∗ ( p 2 . x − p 1 . x ) p 2 . x ∗ p 3 . y − p 1 . x ∗ p 3 . y − p 2 . x ∗ p 4 . y + p 1 . x ∗ p 4 . y − p 4 . x ∗ p 1 . y + p 3 . x ∗ p 1 . y − p 4 . x ∗ p 2 . y + p 3 . x ∗ p 2 . y \small=\frac{(p_1.x*p_2.y-p_2.x*p_1.y)*(p_4.x-p_3.x)-(p_3.x*p_4.y-p_4.x*p_3.y)*(p_2.x-p_1.x)}{p_2.x*p_3.y-p_1.x*p_3.y-p_2.x*p_4.y+p_1.x*p_4.y-p_4.x*p_1.y+p_3.x*p_1.y-p_4.x*p_2.y+p_3.x*p_2.y} =p2.x∗p3.y−p1.x∗p3.y−p2.x∗p4.y+p1.x∗p4.y−p4.x∗p1.y+p3.x∗p1.y−p4.x∗p2.y+p3.x∗p2.y(p1.x∗p2.y−p2.x∗p1.y)∗(p4.x−p3.x)−(p3.x∗p4.y−p4.x∗p3.y)∗(p2.x−p1.x)
= ( p 1 . x ∗ p 2 . y − p 2 . x ∗ p 1 . y ) ∗ ( p 4 . x − p 3 . x ) − ( p 3 . x ∗ p 4 . y − p 4 . x ∗ p 3 . y ) ∗ ( p 2 . x − p 1 . x ) ( ( p 1 . x − p 3 . x ) ∗ ( p 4 . y − p 3 . y ) − ( p 4 . x − p 3 . x ) ∗ ( p 1 . y − p 3 . y ) ) − ( ( p 2 . x − p 3 . x ) ∗ ( p 4 . y − p 3 . y ) ) − ( p 4 . x − p 3 . x ) ( p 2 . y − p 3 . y ) \small=\frac{(p_1.x*p_2.y-p_2.x*p_1.y)*(p_4.x-p_3.x)-(p_3.x*p_4.y-p_4.x*p_3.y)*(p_2.x-p_1.x)}{((p_1.x-p_3.x)*(p_4.y-p_3.y)-(p_4.x-p_3.x)*(p_1.y-p_3.y))-((p_2.x-p_3.x)*(p_4.y-p_3.y))-(p_4.x-p_3.x)(p_2.y-p_3.y)} =((p1.x−p3.x)∗(p4.y−p3.y)−(p4.x−p3.x)∗(p1.y−p3.y))−((p2.x−p3.x)∗(p4.y−p3.y))−(p4.x−p3.x)(p2.y−p3.y)(p1.x∗p2.y−p2.x∗p1.y)∗(p4.x−p3.x)−(p3.x∗p4.y−p4.x∗p3.y)∗(p2.x−p1.x)
= m u l ( p 1 , p 4 , p 3 ) ∗ p 2 . x − m u l ( p 2 , p 4 , p 3 ) ∗ p 1 . x m u l ( p 1 , p 4 , p 3 ) − m u l ( p 2 , p 4 , p 3 ) =\frac{mul(p_1,p_4,p_3)*p_2.x-mul(p_2,p_4,p_3)*p_1.x}{mul(p_1,p_4,p_3)-mul(p_2,p_4,p_3)} =mul(p1,p4,p3)−mul(p2,p4,p3)mul(p1,p4,p3)∗p2.x−mul(p2,p4,p3)∗p1.x
同理, y = m u l ( p 1 , p 4 , p 3 ) ∗ p 2 . y − m u l ( p 2 , p 4 , p 3 ) ∗ p 1 . y m u l ( p 1 , p 4 , p 3 ) − m u l ( p 2 , p 4 , p 3 ) y=\frac{mul(p_1,p_4,p_3)*p_2.y-mul(p_2,p_4,p_3)*p_1.y}{mul(p_1,p_4,p_3)-mul(p_2,p_4,p_3)} y=mul(p1,p4,p3)−mul(p2,p4,p3)mul(p1,p4,p3)∗p2.y−mul(p2,p4,p3)∗p1.y
很具体有木有?
接下来就是比较主要的部分了。
对于新加进来的一个半平面,
我们会出现以下的情况:
!pd(jd(sglist[tail],sglist[tail-1]),seg[i]))
也就是 s e g t a i l − 1 , s e g t a i l + 1 seg_{tail-1},seg_{tail+1} segtail−1,segtail+1的交点在新半平面交(直线方向左边)外,如图:
2.同样的,也有:
所以我们要开一个类似单调队列的队列,来维护这个半平面交。
特别地,在所有线段都被遍历过之后,我们还需要:
while(head<tail&&!pd(jd(sglist[tail],sglist[tail-1]),sglist[head]))--tail;
这是因为:
接下来就是求交点了。
pl=0;for(int i=head+1;i<=tail;i++)plist[++pl]=jd(sglist[i-1],sglist[i]);
plist[++pl]=jd(sglist[head],sglist[tail]);
最后喜闻乐见求面积。
对了这道题还有边界。
SCY讲得还行。
就不赘叙了。
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define eps 1e-8
using namespace std;
const int N=2e4+10;
const double Maxn=1e5;
const double Minn=-1e5;
struct point{double x,y;}plist[N];int pl;
struct segment
{
point p1,p2;
double angle;
segment(){}
segment(double x1,double y1,double x2,double y2)
{p1.x=x1,p1.y=y1;p2.x=x2,p2.y=y2;angle=atan2(p2.y-p1.y,p2.x-p1.x);}
}sglist[N],seg[N];int n,head,tail;
double mul(point p1,point p2,point p0)
{
double x1=p1.x-p0.x,x2=p2.x-p0.x;
double y1=p1.y-p0.y,y2=p2.y-p0.y;
return x1*y2-x2*y1;
}
point jd(segment sg1,segment sg2)
{
double t1=mul(sg1.p1,sg2.p2,sg2.p1);
double t2=mul(sg1.p2,sg2.p2,sg2.p1);
point p1=sg1.p1,p2=sg1.p2,p;
p.x=(t1*p2.x-t2*p1.x)/(t1-t2);
p.y=(t1*p2.y-t2*p1.y)/(t1-t2);
return p;
}
bool pd(point p,segment sg){return mul(p,sg.p2,sg.p1)<=eps;}
bool cmp(segment sg1,segment sg2)
{
if(sg1.angle<sg2.angle)return true;
if(fabs(sg1.angle-sg2.angle)<eps&&pd(sg1.p1,sg2))return true;
return false;
}
void SI()
{
sort(seg+1,seg+n+1,cmp);
int tp=1;for(int i=2;i<=n;i++)if(seg[i].angle-seg[tp].angle>eps)seg[++tp]=seg[i];
n=tp;head=1;tail=2;
sglist[1]=seg[1];sglist[2]=seg[2];
for(int i=3;i<=n;i++)
{
while(head<tail&&!pd(jd(sglist[tail],sglist[tail-1]),seg[i]))--tail;
while(head<tail&&!pd(jd(sglist[head],sglist[head+1]),seg[i]))++head;
sglist[++tail]=seg[i];
}
while(head<tail&&!pd(jd(sglist[tail],sglist[tail-1]),sglist[head]))--tail;
if(tail-head+1<=2){puts("0.0");return ;}
pl=0;for(int i=head+1;i<=tail;i++)plist[++pl]=jd(sglist[i-1],sglist[i]);
plist[++pl]=jd(sglist[head],sglist[tail]);
double ans=0;for(int i=3;i<=pl;i++)ans+=mul(plist[i-1],plist[i],plist[1]);
printf("%.1lf\n",fabs(ans)/2.0);
}
int main()
{
scanf("%d",&n);
seg[1]=segment(Maxn,Maxn,Minn,Maxn);
seg[2]=segment(Minn,Maxn,Minn,Minn);
seg[3]=segment(Minn,Minn,Maxn,Minn);
seg[4]=segment(Maxn,Minn,Maxn,Maxn);
for(int i=1;i<=n;i++)
{
double x1,y1,x2,y2;scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
seg[i+4]=segment(x1,y1,x2,y2);
}
n+=4;
SI();
return 0;
}