码迷,mamicode.com
首页 > 其他好文 > 详细

半平面交

时间:2019-01-01 23:54:45      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:维护   平面   efi   print   --   amp   double   ace   sync   

题解:

把n凸边型转化为n条边后

等价于给出k条直线,让你求直线左边区域的交

然后大概步骤是

首先要给边排序,按照极角从-pai开始逆时针排序

另外平行边我们只需要保留那条约束条件更强的

维护一个双端队列

加点之后判断$(p[h],p[h+1])$的交点$(p[t-1],p[t])$的交点是否在当前直线右边

如果是就不断循环暴力弹

做完之后由于把最后的平面都直接加进来了,所以还要删除没用的

就是$(p[t],p[t-1])$在$p[h]$右边的

代码:

#include <bits/stdc++.h>
using namespace std;
#define rint register int
#define IL inline
#define rep(i,h,t) for (int i=h;i<=t;i++)
#define dep(i,t,h) for (int i=t;i>=h;i--)
const int N=2e5;
const double eps=1e-6;
struct point
{
  double a,b;
  point operator +(point o)
  {
    return (point){a+o.a,b+o.b};
  }
  point operator -(point o)
  {
    return (point){a-o.a,b-o.b};
  }
  point operator *(double x)
  {
    return (point){x*a,x*b};
  }
  point operator /(double x)
  {
    return (point){a/x,b/x};
  }
  double operator *(point x)
  {
    return x.a*a+x.b*b;
  }
  double operator ^(point x)
  {
    return a*x.b-x.a*b;
  }
}p[N],a[N];
struct line
{
  point a,b;
}s[N],l[N];
int tt,st,m;
IL bool pd(line x,line y)
{
  double tt=x.b^y.b;
  return (tt>0||(tt==0&&(x.b^(y.a-x.a))>0));
}
bool cmp(line x,line y)
{
  if (x.b.b==0&&y.b.b==0) return x.b.a<y.b.a;
  if ((x.b.b<=0&&y.b.b<=0)||(x.b.b>0&&y.b.b>0)) return pd(x,y);
  return x.b.b<y.b.b;
}
bool pd2(line x,line y)
{
  return x.b^y.b;
}
bool pd3(point x,line y)
{
  return (y.b^(x-y.a))<=0;
}
point get_j(line x,line y)
{
  double k=(y.a-x.a)^y.b/(x.b^y.b);
  return x.a+(x.b*k);
}
IL double area(point a,point b,point c)
{
  return (abs)((b-a)^(c-a));
}
void solve()
{
  sort(l+1,l+m+1,cmp);
  int tp=0;
  rep(i,1,m)
  {
    if(i==1||pd2(l[i],l[i-1])) tp++;
    l[tp]=l[i];
  }
  m=tp;
  int h=1,t=2;
  s[1]=l[1],s[2]=l[2];
  rep(i,3,m)
  {
    while (h<t&&pd3(get_j(s[t],s[t-1]),l[i])) t--;
    while (h<t&&pd3(get_j(s[h],s[h+1]),l[i])) h++;
    s[++t]=l[i];
  }
  while (h<t&&pd3(get_j(s[t],s[t-1]),s[h])) t--;
  if (t-h<=1) {printf("0.000"); return;}
  tp=0;
  s[h-1]=s[t];
  rep(i,h,t) a[++tp]=get_j(s[i],s[i-1]);
  double ans=0;
  rep(i,3,tp) ans+=area(a[1],a[i-1],a[i])/2;
  printf("%.3lf",ans);
}
int main()
{
  ios::sync_with_stdio(false);
  int tt;
  cin>>tt;
  int n=0;
  while (tt--)
  {
    int k;
    cin>>k;
    int st=n+1;
    while (k--)
    {
      double x,y;
      cin>>x>>y;
      p[++n]=(point){x,y};
      if (n>st) l[++m]=(line){p[n-1],p[n]-p[n-1]};
    }
    l[++m]=(line){p[n],p[st]-p[n]};
  }
  solve();
  return 0; 
}

 

半平面交

标签:维护   平面   efi   print   --   amp   double   ace   sync   

原文地址:https://www.cnblogs.com/yinwuxiao/p/10206388.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!