bzoj2618[Cqoi2006]凸多边形 半平面交

这是一道半平面交的裸题,第一次写半平面交,就说一说我对半平面交的理解吧。

所谓半平面交,就是求一大堆二元一次不等式的交集,而每个二元一次不等式的解集都可以看成是在一条直线的上方或下方,联系直线的标准方程就可以得出。于是乎这些不等式就可以转化为一些半平面,求的就是半平面交。

而半平面交不可能交出凹多边形(因为凹多边形的定义是有一条边所在的直线能把该多边形分成若干块。。。YY一下就知道这是不可能的),这是一个十分优美的性质,正类似于凸包(写法也是有些相似的),但半平面交可能交出无界,于是可以加四条类似于一个框的直线将这个区域框起来,就可以避免无界情况的出现,当然也可能交出无解,一个点或一条直线(俩点),判一判就好了。

有一个十分暴力的n^2做法,就是每次加一条直线,暴力去判与当前直线的交点,然后判断哪些部分不可行,哪些部分可行。。。(十分暴力,而且十分难写。。。。)

也有两个(可能是三个。。。不过后两个思想类似)nlogn的做法,一种是分治,将当前的半平面数分治,递归去找,然后利用扫描线扫过去。。。。不过常数大而且不易编写

还有另一个nlogn的做法,就是维护一个单调栈,用一个上凸壳和一个下凸壳处理,方法是如果直线stack[top]与当前直线a[i]交点在当前的半平面外就top--,然后把得到的一个上凸壳和一个下凸壳合并即可

但合并还是有些麻烦,就可以用一个双向队列维护一个凸壳,每次加入一条直线就判队头和队尾然后加在队尾,但具体实现过程中可能会出现问题,因为令极角递增(都是看成逆时针旋转,这样比较方便),所以当前直线的极角一定比队列中所有直线的极角都要大,因此对答案是一定有贡献的(也就是一定会是边界,在不被后面的直线判掉的情况下),在维护两个单调栈时并不用考虑(貌似合并时也要考虑),但deque是一个环,因此到最后的直线的斜率虽然大,但并不一定会对半平面产生贡献(毕竟每一次都是queue[++tail]=a[i]),因此就还需要两遍while判队头队尾什么的。这样十分方便而且核心代码巨短。。。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 #define maxn 2000
 8 #define eps 1e-0
 9
10 int n,m,tot,cnt;
11
12 struct point{
13     double x,y;
14 }p[maxn],pt[maxn];
15
16 struct line{
17     point from,to;
18     double slope;
19 }l[maxn],q[maxn];
20
21 point operator -(point a,point b){return(point){a.x-b.x,a.y-b.y};}
22 point operator +(point a,point b){return(point){a.x+b.x,a.y+b.y};}
23 double operator *(point a,point b){return a.x*b.y-a.y*b.x;}
24 bool operator <(line a,line b){
25     return (a.slope==b.slope)?((a.to-a.from)*(b.to-a.from)<0):a.slope<b.slope;
26 }
27 bool operator ==(line a,line b){
28     return a.slope==b.slope;
29 }
30
31 point getpoint(line a,line b){
32     double t1=(b.to-a.from)*(a.to-a.from),t2=(a.to-a.from)*(b.from-a.from);
33     double t=t1/(t1+t2);
34     return (point){(b.from.x-b.to.x)*t+b.to.x,(b.from.y-b.to.y)*t+b.to.y};
35 }
36
37 bool check(line a,line b,line c){
38     point d=getpoint(a,b);
39     return (c.to-c.from)*(d-c.from)<0;
40 }
41
42 void solve(){
43     int head=1,tail=2;
44     q[1]=l[1],q[2]=l[2];
45     for (int i=3;i<=n;i++){
46         while (head<tail && check(q[tail-1],q[tail],l[i])) tail--;
47         while (head<tail && check(q[head+1],q[head],l[i])) head++;
48         q[++tail]=l[i];
49     }
50     while (head<tail && check(q[tail-1],q[tail],q[head])) tail--;
51     while (head<tail && check(q[head+1],q[head],q[tail])) head++;
52     q[tail+1]=q[head],cnt=0;
53     for (int i=head;i<=tail;i++) pt[++cnt]=getpoint(q[i],q[i+1]);
54 }
55
56 int main(){
57     scanf("%d",&n);
58     for (int i=1;i<=n;i++){
59         scanf("%d",&m);
60         for (int j=1;j<=m;j++) scanf("%lf %lf",&p[j].x,&p[j].y);
61         p[m+1]=p[1];
62         for (int j=1;j<=m;j++) l[++tot].from=p[j],l[tot].to=p[j+1];
63     }
64     for (int i=1;i<=tot;i++) l[i].slope=atan2(l[i].to.y-l[i].from.y,l[i].to.x-l[i].from.x);
65     sort(l+1,l+tot+1);
66     n=0;
67     n=unique(l+1,l+tot+1)-l;
68     n--;
69     solve();
70     double ans=0;
71     if (cnt<=2){
72         printf("0.000");
73         return 0;
74     }
75     pt[++cnt]=pt[1];
76     for (int i=1;i<=cnt;i++) ans+=pt[i]*pt[i+1];
77     printf("%.3lf",ans/2);
78     return 0;
79 }

时间: 2024-12-28 23:44:16

bzoj2618[Cqoi2006]凸多边形 半平面交的相关文章

【bzoj2618】[Cqoi2006]凸多边形 半平面交

题目描述 逆时针给出n个凸多边形的顶点坐标,求它们交的面积.例如n=2时,两个凸多边形如下图: 则相交部分的面积为5.233. 输入 第一行有一个整数n,表示凸多边形的个数,以下依次描述各个多边形.第i个多边形的第一行包含一个整数mi,表示多边形的边数,以下mi行每行两个整数,逆时针给出各个顶点的坐标. 输出 输出文件仅包含一个实数,表示相交部分的面积,保留三位小数. 样例输入 2 6 -2 0 -1 -2 1 -2 2 0 1 2 -1 2 4 0 -3 1 -1 2 2 -1 0 样例输出

BZOJ 2618 CQOI2006 凸多边形 半平面交

题目大意:给定n个凸多边形,求交集的面积 时隔多年我终于把完整的半平面交搞出来了--真尼玛艰辛-- 曾经写了一发 RE到死 于是就搁置0.0 今天写一发又是WA到死的节奏-- 不多说直接上代码 其实刘汝佳同学写麻烦了 每次插入一个半平面之后不用两端都删的 只删一端 最后再处理两端的部分就行 300题留念--切了道模板题也不错 #include <cmath> #include <cstdio> #include <cstring> #include <iostre

bzoj2618 凸多边形 半平面交

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2618 题意:求出几个封闭图形围成的内部区域面积. 把每一条边作为有向直线,逆时针遍历全图,左侧的半平面交 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace s

BZOJ 2618 CQOI 2006 凸多边形 半平面交

题目大意:给出n个凸多边形,求这些多边形的面积的交. 思路:犯傻了..以后看到凸多边形第一时间就要想到半平面交啊..多明显啊,半天愣着没想出来. CODE: #include <cmath> #include <cstdio> #include <iomanip> #include <cstring> #include <iostream> #include <algorithm> #define MAX 6100 #define E

关于半平面交

嗯,这是一个很屌的东西.可以把他想象成数学中的线性规划问题,然后自然而然得想到就可以求最优解啦. 如何求解半平面交????? 做法一:暴力枚举点,用该点切割现有的凸多边形,这样的复杂度是O(n^2) 做法二:神奇的分治O(nlogn),然而我并不会.... 做法三:参见2006年朱泽园大神发明的排序增量法:这里就暂时不给详细介绍了. 复杂度O(nlogn),如果把快速排序改成基数排序,复杂度可以进一步降为:O(n)!!!!!! 半平面交的另外一个应用是求多边形的核:可以想象成站在一个多边形的点上

POJ3525 半平面交

题意:求某凸多边形内部离边界最远的点到边界的距离 首先介绍半平面.半平面交的概念: 半平面:对于一条有向直线,它的方向的左手侧就是它所划定的半平面范围.如图所示: 半平面交:多个半平面的交集.有点类似二元函数的线性规划.如图 求半平面交:用的kuangbin模板= = sol:二分答案 二分距离值,按这个值把边界向内缩,再求新的半平面交.如图: 绿色的是原图形,蓝色是按距离值向里面缩进去之后得到的新图形.对这个新图做半平面交即可. 若半平面交存在,说明与边界的距离是该值的点存在(半平面交里面的点

BZOJ 1137: [POI2009]Wsp 岛屿 半平面交

1137: [POI2009]Wsp 岛屿 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 165  Solved: 78[Submit][Status][Discuss] Description Byteotia岛屿是一个凸多边形.城市全都在海岸上.按顺时针编号1到n.任意两个城市之间都有一条笔直的道路相连.道路相交处可以自由穿行.有一些道路被游击队控制了,不能走,但是可以经过这条道路与未被控制的道路的交点.问

BZOJ2618 [Cqoi2006]凸多边形

那个叫啥,半平面交... 第一次写于是只能按照惯例,orz hzwer去~~~ 把一个凸多边形搞成好多条线段,于是题目就变成了一堆线段的半平面交... 怎么感觉比仙人掌还简单一点的说...就是有点长 1 /************************************************************** 2 Problem: 2618 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time:0 ms 7 Memo

HDU 2297 半平面交

Run Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 640    Accepted Submission(s): 181 Problem Description Since members of Wuhan University ACM Team are lack of exercise, they plan to particip