当前位置: 首页 > news >正文

半平面交模板

妹的,一直没有想清楚无解的情况到底是如何判断的。

偷来一个模板。

半平面交的结果:1.凸多边形(后面会讲解到)2.无界,因为有可能若干半平面没有形成封闭3.直线,线段,点,空(属于特殊情况吧)

算法:1:根据上图可以知道,运用给出的多边形每相邻两点形成一条直线来切割原有多边形,如果多边形上的点i在有向直线的左边或者在直线上即保存起来,否则判断此点的前一个点i-1和后一个点i+1是否在此直线的左边或线上,在的话分别用点i和点i-1构成的直线与此时正在切割的直线相交求出交点,这个交点显然也要算在切割后剩下的多边形里,同理点i和点i+1。原多边形有n条边,每条边都要进行切割,所以时间复杂度为O(n^2)。

2:第二种就是训练指南上面详细讲解的运用双端队列的半平面交算法,时间复杂度为O(nlogn)。仔细阅读代码应该能理解。

代码实现:以 poj3130 为例,裸的模板。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 0x7fffffff
#define exp 1e-10
#define PI 3.141592654
using namespace std;
const int maxn=111;
struct Point
{
    double x,y;
    Point (double x=0,double y=0):x(x),y(y){}
}an[maxn],bn[maxn],cn[maxn];
///an:记录最开始的多边形;bn:临时保存新切割的多边形;cn:保存新切割出的多边形
typedef Point Vector;
Vector operator + (Vector A,Vector B) {return Vector(A.x+B.x , A.y+B.y); }
Vector operator - (Vector A,Vector B) {return Vector(A.x-B.x , A.y-B.y); }
Vector operator * (Vector A,double p) {return Vector(A.x*p , A.y*p); }
Vector operator / (Vector A,double p) {return Vector(A.x/p , A.y/p); }
int dcmp(double x) {if (fabs(x)<exp) return 0;return x>0 ? 1 : -1;  }
double cross(Vector A,Vector B)
{
    return A.x*B.y-B.x*A.y;
}

double A,B,C;
int n,m;
void getline(Point a,Point b)///获取直线 Ax + By + C = 0
{
    A=b.y-a.y;
    B=a.x-b.x;
    C=b.x*a.y-a.x*b.y;
}
///getline()函数得到的直线和点a和点b所连直线的交点
Point intersect(Point a,Point b)
{
    double u=fabs(A*a.x+B*a.y+C);
    double v=fabs(A*b.x+B*b.y+C);
    Point ans;
    ans.x=(a.x*v+b.x*u)/(u+v);
    ans.y=(a.y*v+b.y*u)/(u+v);
    return ans;
}
void cut()///切割,原多边形的点为顺时针存储
{
    int cnt=0;
    for (int i=1 ;i<=m ;i++)
    {
        if (A*cn[i].x + B*cn[i].y + C>=0) bn[++cnt]=cn[i];
        else
        {
            if (A*cn[i-1].x + B*cn[i-1].y + C > 0) bn[++cnt]=intersect(cn[i-1],cn[i]);
            if (A*cn[i+1].x + B*cn[i+1].y + C > 0) bn[++cnt]=intersect(cn[i+1],cn[i]);
        }
    }
    for (int i=1 ;i<=cnt ;i++) cn[i]=bn[i];
    cn[0]=bn[cnt];
    cn[cnt+1]=bn[1];
    m=cnt;///新切割出的多边形的点数
}
void solve()
{
    for (int i=1 ;i<=n ;i++) cn[i]=an[i];
    an[n+1]=an[1];
    cn[n+1]=an[1];
    cn[0]=an[n];
    m=n;
    for (int i=1 ;i<=n ;i++)
    {
        getline(an[i],an[i+1]);
        cut();
    }
}
int main()
{
    while (scanf("%d",&n)!=EOF && n)
    {
        for (int i=1 ;i<=n ;i++) scanf("%lf%lf",&an[i].x,&an[i].y);
        reverse(an+1,an+n+1);
        solve();
        if (m) puts("1");
        else puts("0");
    }
    return 0;
}

 


View Code

poj3335 ,给出两种方法

1.O(n^2)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 0x7fffffff
#define exp 1e-10
#define PI 3.141592654
using namespace std;
const int maxn=111;
struct Point
{
    double x,y;
    Point (double x=0,double y=0):x(x),y(y){}
}an[maxn],bn[maxn],cn[maxn];
typedef Point Vector ;
Vector operator + (Vector A,Vector B) {return Vector(A.x+B.x , A.y+B.y); }
Vector operator - (Vector A,Vector B) {return Vector(A.x-B.x , A.y-B.y); }
Vector operator * (Vector A,double p) {return Vector(A.x*p , A.y*p); }
Vector operator / (Vector A,double p) {return Vector(A.x/p , A.y/p); }
int dcmp(double x) {if (fabs(x)<exp) return 0;return x>0 ? 1 : -1; }
double cross(Vector A,Vector B)
{
    return A.x*B.y-B.x*A.y;
}

int n,m;
double A,B,C;
void getline(Point a,Point b)
{
    A=b.y-a.y;
    B=a.x-b.x;
    C=b.x*a.y-a.x*b.y;
}
Point intersect(Point a,Point b)
{
    double u=fabs(A*a.x+B*a.y+C);
    double v=fabs(A*b.x+B*b.y+C);
    Point ans;
    ans.x=(a.x*v+b.x*u)/(u+v);
    ans.y=(a.y*v+b.y*u)/(u+v);
    return ans;
}
void cut()
{
    int cnt=0;
    for (int i=1 ;i<=m ;i++)
    {
        if (A*cn[i].x+B*cn[i].y+C>=0)
            bn[++cnt]=cn[i];
        else
        {
            if (A*cn[i-1].x+B*cn[i-1].y+C>0)
                bn[++cnt]=intersect(cn[i-1],cn[i]);
            if (A*cn[i+1].x+B*cn[i+1].y+C>0)
                bn[++cnt]=intersect(cn[i+1],cn[i]);
        }
    }
    for (int i=1 ;i<=cnt ;i++) cn[i]=bn[i];
    cn[0]=bn[cnt];
    cn[cnt+1]=bn[1];
    m=cnt;
}
void solve()
{
    for (int i=1 ;i<=n ;i++) cn[i]=an[i];
    an[n+1]=an[1];
    cn[n+1]=cn[1];
    cn[0]=cn[n];
    m=n;
    for (int i=1 ;i<=n ;i++)
    {
        getline(an[i],an[i+1]);
        cut();
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d",&n);
        for (int i=1 ;i<=n ;i++) scanf("%lf%lf",&an[i].x,&an[i].y);
        solve();
        if (!m) printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}

 


View Code

2.O(nlogn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define inf 0x7fffffff
#define exp 1e-10
#define PI 3.141592654
using namespace std;
const int maxn=111;
struct Point
{
    double x,y;
    Point (double x=0,double y=0):x(x),y(y){}
}an[maxn];
typedef Point Vector;
struct Line
{
    Point p;
    Vector v;
    double ang;
    Line (){}
    Line (Point p,Vector v):p(p),v(v){ang=atan2(v.y,v.x); }
    //Line (Point p,Vector v):p(p),v(v) {ang=atan2(v.y,v.x); }
    friend bool operator < (Line a,Line b)
    {
        return a.ang<b.ang;
    }
}bn[maxn];
Vector operator + (Vector A,Vector B) {return Vector(A.x+B.x , A.y+B.y); }
Vector operator - (Vector A,Vector B) {return Vector(A.x-B.x , A.y-B.y); }
Vector operator * (Vector A,double p) {return Vector(A.x*p , A.y*p); }
Vector operator / (Vector A,double p) {return Vector(A.x/p , A.y/p); }
int dcmp(double x) {if (fabs(x)<exp) return 0;return x>0 ? 1 : -1; }
double cross(Vector A,Vector B)
{
    return A.x*B.y-B.x*A.y;
}
bool OnLeft(Line L,Point p)
{
    return cross(L.v,p-L.p)>=0;///点P在有向直线L的左边(>=0说明在线上也算)
}
Point GetIntersection(Line a,Line b)
{
    Vector u=a.p-b.p;
    double t=cross(b.v,u)/cross(a.v,b.v);
    return a.p+a.v*t;
}
//Point GetIntersection(Line l1, Line l2) {
//    Point p;
//    double dot1,dot2;
//    //dot1 = multi(l2.a, l1.b, l1.a);
//    dot1=cross(l1.b-l2.a , l1.a-l2.a);
//    //dot2 = multi(l1.b, l2.b, l1.a);
//    dot2=cross(l2.b-l1.b , l1.a-l1.b);
//    p.x = (l2.a.x * dot2 + l2.b.x * dot1) / (dot2 + dot1);
//    p.y = (l2.a.y * dot2 + l2.b.y * dot1) / (dot2 + dot1);
//    return p;
//}
int HalfplaneIntersection(Line *L,int n,Point *poly)
{
    sort(L,L+n);

    int first,last;
    Point *p=new Point[n];
    Line *q=new Line[n];
    q[first=last=0]=L[0];
    for (int i=1 ;i<n ;i++)
    {
        while (first<last && !OnLeft(L[i],p[last-1])) last--;
        while (first<last && !OnLeft(L[i],p[first])) first++;
        q[++last]=L[i];
        if (fabs(cross(q[last].v , q[last-1].v))<exp)
        {
            last--;
            if (OnLeft(q[last] , L[i].p)) q[last]=L[i];
        }
        if (first<last) p[last-1]=GetIntersection(q[last-1],q[last]);
    }
    while (first<last && !OnLeft(q[first],p[last-1])) last--;
    if (last-first<=1) return 0;
    p[last]=GetIntersection(q[last],q[first]);
    int m=0;
    for (int i=first ;i<=last ;i++) poly[m++]=p[i];
    return m;
}
void calPolygon(Point *p, int n, double &area, bool &shun)
{
    p[n] = p[0];
    area = 0;
    double tmp;
    for (int i = 0; i < n; i++)
        area += p[i].x * p[i + 1].y - p[i].y * p[i + 1].x;
    area /= 2.0;
    if (shun = area < 0)
        area = -area;
}
bool calCore(Point *ps, int n)
{
    Line l[maxn];
    ps[n] = ps[0];
    bool shun;
    double area;
    calPolygon(ps, n, area, shun);
    if (shun)
        for (int i = 0; i < n; i++)
            bn[i] = Line(ps[i], ps[i] - ps[i + 1]);
    else
        for (int i = 0; i < n; i++)
            bn[i] = Line(ps[i], ps[i + 1] - ps[i]);
    Point pp[maxn];
    return HalfplaneIntersection(bn, n, pp);
}
int main()
{
    int t;
    int n;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d",&n);
        Point cn[maxn];
        for (int i=0 ;i<n ;i++)
        {
            scanf("%lf%lf",&cn[i].x,&cn[i].y);
        }
//        reverse(cn,cn+n);
//        for (int i=0 ;i<n ;i++)
//        {
//            bn[i].p=cn[i];
//            bn[i].v=cn[(i+1)%n]-cn[i];
//            bn[i].ang=atan2(bn[i].v.y , bn[i].v.x);
//        }
//        int m=HalfplaneIntersection(bn,n,an);
        if (!calCore(cn,n)) puts("NO");
        else puts("YES");
    }
    return 0;
}

 

练习:

poj 1474 

poj 2451

poj 3525

LA 2218

LA 2512

UVA 10084

后续:欢迎提出宝贵的意见。

相关文章:

  • 观察站模式
  • Fiddler 抓包工具总结
  • iOS:iOS开发中用户密码保存位置
  • 在windows下如何快速搭建web.py开发框架
  • 八个最优秀的Android Studio插件
  • 游戏保护大放送之GPK
  • 面向对象之多态
  • 老板突然走了-被诏安
  • 免费的在线Web文件管理器:Net2FTP,Pydio,eXtplorer,KodExplorer–功能强大
  • 常用笔记本规格表
  • 《构建之法》阅读梳理篇读后感
  • 如何下载一些网站本身不希望你下载的文件呢
  • 如何查看PC和Windows Mobile下蓝牙(Bluetooth)的Stack
  • 单页面应用SPA架构
  • 从Windows到Android开发
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • github从入门到放弃(1)
  • golang中接口赋值与方法集
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • Python打包系统简单入门
  • React Native移动开发实战-3-实现页面间的数据传递
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 高度不固定时垂直居中
  • 关于Flux,Vuex,Redux的思考
  • 来,膜拜下android roadmap,强大的执行力
  • 每天一个设计模式之命令模式
  • 如何借助 NoSQL 提高 JPA 应用性能
  • 事件委托的小应用
  • 王永庆:技术创新改变教育未来
  • 微信支付JSAPI,实测!终极方案
  • 用 Swift 编写面向协议的视图
  • postgresql行列转换函数
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • #AngularJS#$sce.trustAsResourceUrl
  • #includecmath
  • #pragma pack(1)
  • (07)Hive——窗口函数详解
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • .jks文件(JAVA KeyStore)
  • .NET MVC第三章、三种传值方式
  • .NET Standard 的管理策略
  • .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调
  • .net的socket示例
  • .net对接阿里云CSB服务
  • .Net环境下的缓存技术介绍
  • @RequestMapping用法详解
  • [ vulhub漏洞复现篇 ] ECShop 2.x / 3.x SQL注入/远程执行代码漏洞 xianzhi-2017-02-82239600
  • [Android] 修改设备访问权限
  • [Contiki系列论文之2]WSN的自适应通信架构
  • [IE6 only]关于Flash/Flex,返回数据产生流错误Error #2032的解决方式
  • [IE技巧] 使IE8以单进程的模式运行
  • [leetcode] Balanced Binary Tree
  • [NAND Flash 6.2] NAND 初始化常用命令:复位 (Reset) 和 Read ID 和 Read UID 操作和代码实现