sgu 345-Revolution

来源:互联网 发布:淘宝售后制度 编辑:程序博客网 时间:2024/05/17 02:28

题目大意:

      输入n个点,求凸包。然后给出m条直线,每次询问被直线切割的凸包的两部分面积的较小值。


分析:

      本题是一个难度较大的计算几何题,难就难在求直线切割凸包,至于凸包的求法我就不再阐述了,就是Graham贪心法。凸包求出来之后呢,因为有m条直线,所以直线的询问带来了O(m)的时间复杂度,所以求凸包与直线的交点肯定要是对数级的。我们考虑要求凸包与直线的交点,如图:

      要求直线与凸包的交点首先可以明确一点,如果找到了凸包上离直线最远的两个点那么直线与凸包的两个交点分别在以这两个最远点为分界点的半凸壳上,首先我们要找到那两个最远点。我们可以将凸包看成由一组向量围成的凸多边形,直线也看作向量,如图:


 

      易证明若是凸包上有一组相邻向量,它们的极角(即为与x轴正方向夹的正角)一个比向量JI小,一个比它大,那么这两个相邻向量的中间点即为第一个最远点。再将向量JI取反,再求出一个类似的点即为第二个最远点。知道了这个性质,那么我们怎么求呢?

      首先可以明确一个性质,凸包的向量极角从第一个点开始的向量到第一个点结束的向量是单增的。那么我们可以依据这个单调性二分,以防出现BUG,先特判一下第一个和第最后一个点是不是最远点,再二分就行了(我用的判断极角的办法非常丑陋,先判断象限,象限相同就叉积,左拐的较大)。这样我们就可以二分找到两个最远点了。时间复杂度O(log2(n))

      现在就是需要在以这两个最远点为分界点的半凸壳上找到凸包与直线的交点,我们又可以发现一个神奇的性质,如图:


      我们将一个半凸壳上的所有点向这条直线做垂线,不难发现,沿着向量方向,凸包上的点离直线的距离先减小后增大,就说明凸包上的点到直线的距离沿向量方向是单峰极值函数,我们可以采用三分法求解出在当前半凸壳上离直线最近的点,时间复杂度O(log3(n))那么,那个点相邻的两条线段肯定有和直线相交的,所以,三分求出两个半凸壳上的两个最近点,判断四条线段与直线的位置关系,若交点数<2则没有交点,即直接输出0,否则就可以求出那两个交点。

      还有一个小问题,求出交点之后怎么求面积,因为凸包分割后总是有一圈是凸包上的连续的一组向量,算面积我们是用叉积,所以采用前缀和,sum[i]表示从1开始的向量叉积到以i为结尾向量的和,前缀和完美解决这个问题!总时间复杂度O(nlog2(n)+m(log2(n)+log3(n)))。

      ps:代码很丑,两百多行,后面用了大量人工智能。十组数据在机房电脑上跑了8s多,一百组数据在sgu上跑了0.8s多,不解释。。。


Source:

sgu 345-Revolution
原创粉丝点击