关于半平面交

嗯,这是一个很屌的东西。可以把他想象成数学中的线性规划问题,然后自然而然得想到就可以求最优解啦。

如何求解半平面交?????

做法一:暴力枚举点,用该点切割现有的凸多边形,这样的复杂度是O(n^2)

做法二:神奇的分治O(nlogn),然而我并不会。。。。

做法三:参见2006年朱泽园大神发明的排序增量法:这里就暂时不给详细介绍了。

复杂度O(nlogn),如果把快速排序改成基数排序,复杂度可以进一步降为:O(n)!!!!!!

半平面交的另外一个应用是求多边形的核:可以想象成站在一个多边形的点上,

该点能看到多边形的每一个部位的点集。这个直接求出半平面的面积就可以了。

#include<bits/stdc++.h>
#define N 2000
#define il inline
#define LL long long
#define db double
using namespace std;
struct point{
  db x,y;
  point() {}
  point(db X,db Y):x(X),y(Y) {}
  db operator *(const point & a)const{
    return x*a.y-y*a.x;
  }
  point operator +(const point & a)const{
    return point(x+a.x,y+a.y);
  }
  point operator -(const point & a)const{
    return point(x-a.x,y-a.y);
  }
  point operator *(const db & k)const{
    return point(x*k,y*k);
  }
}p[N];
struct line{
  point a,b;db Ang;
  line() {}
  line(point A,point B,db Aa):a(A),b(B),Ang(Aa) {}
}l[N];
int n;
#define eps 1e-8
il int CC(double kk){
  if(fabs(kk)<eps)return 0;
  return kk>0?1:-1;
}
il bool comp(const line & l1,const line & l2){
  int ff=CC(l1.Ang-l2.Ang);
  if(!ff)return CC((l2.a-l1.a)*(l2.b-l1.a))<0;
  return l1.Ang<l2.Ang;
}
void getnode(line l1,line l2,point & p){
  point a=l1.a,b=l1.b,c=l2.a,d=l2.b;
  db k=((c-a)*(d-c))/((b-a)*(d-c));
  p=a+(b-a)*k;
}
int de[N];
bool check(line l0,line l1,line l2){
  point p;getnode(l1,l2,p);
  return CC((l0.b-l0.a)*(p-l0.a))<0;
}
void HalfplaneIntersect(){
  int j=0;
  sort(l+1,l+n+1,comp);
  l[++j]=l[1];
  for(int i=2;i<=n;++i)
    if(CC(l[i].Ang-l[j].Ang)>0)l[++j]=l[i];
  n=j;de[1]=1,de[2]=2;
  int tail(2),head(1);
  for(int i=3;i<=n;++i){
    while(tail>head&&(!check(l[i],l[de[tail]],l[de[tail-1]])))tail--;
    while(tail>head&&(!check(l[i],l[de[head]],l[de[head+1]])))head++;
    de[++tail]=i;
  }while(tail>head&&(!check(l[de[head]],l[de[tail]],l[de[tail-1]])))tail--;
  while(tail>head&&(!check(l[de[tail]],l[de[head]],l[de[head+1]])))head++;
  int cnt=0;de[++tail]=de[head];
  for(int i=head;i<tail;++i)cnt++,getnode(l[de[i]],l[de[i+1]],p[cnt]);
  n=cnt;
}
db Ans(){
  db cnt=0.00;
  if(n<3)return 0;
  for(int i=2;i<n;++i)cnt+=((p[i]-p[1])*(p[i+1]-p[1]));
  cnt=fabs(cnt);cnt/=2;return cnt;
}
int main(){
  int T;scanf("%d",&T);
  while(T--){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)scanf("%lf%lf",&p[i].x,&p[i].y);
    for(int i=1;i<n;++i)l[i]=line(p[i],p[i+1],atan2(p[i+1].y-p[i].y,p[i+1].x-p[i].x));
    l[n]=line(p[n],p[1],atan2(p[1].y-p[n].y,p[1].x-p[n].x));
    HalfplaneIntersect();printf("%.2lf\n",Ans());
  }
  return 0;
}

  

时间: 2024-12-22 02:35:32

关于半平面交的相关文章

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

计算几何 半平面交

LA 4992 && hdu 3761 Jungle Outpost 杭电的有点坑啊..一直爆内存,后来发现大白的半平面交模板那里 point *p = new point[n]; line *q = new line[n]这里出了问题,应该是在函数里面申请不了比较大的数组,所以爆内存..我在全局定义了两个数组就不会爆了.. 本来跑了17s多的,后来半平面交sort( l, l + n ) 被我注释了,就跑了9s多,LA上跑了 2s..应该是输入数据比较好,不用按照极角排序..然后就是照着

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]凸多边形 半平面交

这是一道半平面交的裸题,第一次写半平面交,就说一说我对半平面交的理解吧. 所谓半平面交,就是求一大堆二元一次不等式的交集,而每个二元一次不等式的解集都可以看成是在一条直线的上方或下方,联系直线的标准方程就可以得出.于是乎这些不等式就可以转化为一些半平面,求的就是半平面交. 而半平面交不可能交出凹多边形(因为凹多边形的定义是有一条边所在的直线能把该多边形分成若干块...YY一下就知道这是不可能的),这是一个十分优美的性质,正类似于凸包(写法也是有些相似的),但半平面交可能交出无界,于是可以加四条类

poj3335 半平面交

题意:给出一多边形.判断多边形是否存在一点,使得多边形边界上的所有点都能看见该点. sol:在纸上随手画画就可以找出规律:按逆时针顺序连接所有点.然后找出这些line的半平面交. 题中给出的点已经按顺时针排好序了,所以只要倒过来一下就可以了.很简单的模板题. 1 #include<vector> 2 #include<list> 3 #include<map> 4 #include<set> 5 #include<deque> 6 #includ

【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 样例输出

POJ 2451 Uyuw&#39;s Concert(半平面交nlgn)

//#pragma comment(linker, "/STACK:16777216") //for c++ Compiler #include <stdio.h> #include <iostream> #include <cstring> #include <cmath> #include <stack> #include <queue> #include <vector> #include <

【BZOJ1007】[HNOI2008]水平可见直线 半平面交

[BZOJ1007][HNOI2008]水平可见直线 Description 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.例如,对于直线:L1:y=x; L2:y=-x; L3:y=0则L1和L2是可见的,L3是被覆盖的.给出n条直线,表示成y=Ax+B的形式(|A|,|B|<=500000),且n条直线两两不重合.求出所有可见的直线. Input 第一行为N(0 < N < 50000