[模板] 计算几何2: 自适应Simpson/凸包/半平面交/旋转卡壳/闵可夫斯基和

//to update

一些基本的定义在这里: [模板] 计算几何1(基础): 点/向量/线/圆/多边形/其他运算

自适应Simpson

凸包

Andrew 算法, 即分别求上, 下凸包. 时间复杂度 \(O(n \log n)\).

struct tvec{db x,y;};

il int dcmp(db a){return fabs(a)<=eps?0:(a>0?1:-1);}
il db p2(db a){return a*a;}
il db gougu1(db a,db b){return sqrt(p2(a)+p2(b));}
il tvec operator+(tvec a,tvec b){return (tvec){a.x+b.x,a.y+b.y};}
il tvec operator-(tvec a,tvec b){return (tvec){a.x-b.x,a.y-b.y};}
il tvec operator*(tvec a,db b){return (tvec){a.x*b,a.y*b};}
il tvec operator*(db a,tvec b){return b*a;}
il db operator*(tvec a,tvec b){return a.x*b.y-b.x*a.y;}
il db operator^(tvec a,tvec b){return a.x*b.x+a.y*b.y;}
il db len(tvec a){return gougu1(a.x,a.y);}
bool cmp(tvec a,tvec b){int tmp=dcmp(a.x-b.x);return tmp?tmp<0:dcmp(a.y-b.y)<0;}

tvec li[nsz],conv[nsz];
int pc=0;
void getconv(){
    sort(li+1,li+n+1,cmp);
    rep(i,1,n){
        while(pc>1&&dcmp((conv[pc]-conv[pc-1])*(li[i]-conv[pc]))<=0)--pc;
        conv[++pc]=li[i];
    }
    int tmp=pc;
    repdo(i,n-1,1){
        while(pc>tmp&&dcmp((conv[pc]-conv[pc-1])*(li[i]-conv[pc]))<=0)--pc;
        conv[++pc]=li[i];
    }
    if(n>1)--pc;
}

半平面交

增量法, 时间复杂度 \(O(n \log n)\) (排序的复杂度).

需要保证不是开放的半平面. 否则加上四个 \(\pm \infty\) 的平面即可.

细节较多. 详见代码...

const int psz=550;
const db eps=1e-9;
int n,m;

db dcmp(db v){return fabs(v)<=eps?0:(v>0?1:-1);}
db p2(db v){return v*v;}

struct tvec{db x,y;};
tvec operator+(tvec a,tvec b){return (tvec){a.x+b.x,a.y+b.y};}
tvec operator-(tvec a,tvec b){return (tvec){a.x-b.x,a.y-b.y};}
tvec operator*(tvec a,db b){return (tvec){a.x*b,a.y*b};}
tvec operator*(db a,tvec b){return b*a;}
db operator*(tvec a,tvec b){return a.x*b.y-a.y*b.x;}
db operator^(tvec a,tvec b){return a.x*b.x+a.y*b.y;}
db len(tvec a){return sqrt(p2(a.x)+p2(a.y));}

struct tl{
    tvec p,v;
    db d;
    tl(){}
    tl(tvec a,tvec b):p(a),v(b-a){d=atan2(v.y,v.x);}
}li[psz];
int pl=0;
bool operator<(tl a,tl b){return a.d<b.d;}
bool isleft(tl a,tvec b){return dcmp(a.v*(b-a.p))>0;}
il tvec inters(tl a,tl b){db v=(b.v*(a.p-b.p))/(a.v*b.v);return a.p+a.v*v;}

tvec poly[psz];
int ppo=0;

tl que[psz]; //queue
tvec qp[psz]; //intersect points
int qh=1,qt=0;
int hplane(){//0 fail, 1 success
    sort(li+1,li+pl+1);
    int pl1=1;//suppose that pl>=1
    rep(i,2,pl){
        if(li[i].d>li[pl1].d)li[++pl1]=li[i];
        else if(isleft(li[pl1],li[i].p))li[pl1]=li[i];
    }
    pl=pl1;
    qh=1,qt=0;
    rep(i,1,pl){
        while(qh<qt&&!isleft(li[i],qp[qt-1]))--qt;
        while(qh<qt&&!isleft(li[i],qp[qh]))++qh;
        que[++qt]=li[i];
        if(qh<qt)qp[qt-1]=inters(que[qt-1],que[qt]);
    }
    while(qh<qt&&!isleft(que[qh],qp[qt-1]))--qt; //**
    ppo=0;
    if(qt-qh<=1)return 0; //no sol
    qp[qt]=inters(que[qh],que[qt]);
    rep(i,qh,qt)poly[++ppo]=qp[i];
    return 1;
}

旋转卡壳

这是一种拥有 \(4\) 个多音字, \(2^4 = 16\) 种读音的优秀算法.

原文地址:https://www.cnblogs.com/ubospica/p/10828219.html

时间: 2024-10-10 15:43:59

[模板] 计算几何2: 自适应Simpson/凸包/半平面交/旋转卡壳/闵可夫斯基和的相关文章

POJ 3608 两凸包最近距离 旋转卡壳

Bridge Across Islands Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8071   Accepted: 2364   Special Judge Description Thousands of thousands years ago there was a small kingdom located in the middle of the Pacific Ocean. The territory

[HDU4316]Mission Impossible(计算几何/凸包/半平面交)

题目链接: HDU4316 计算几何太duliu了~ 题目大意:空间中有一个物体,上空有\(3\)个摄像头拍摄地面,求摄像头公共盲区面积大小 首先求出每一个摄像头的盲区: 将物体的每一个点投影到地面再求凸包即可. 然后将\(3\)个凸包的每一条边都拿来一起做一次半平面交,求出公共盲区 最后三角剖分求面积就好了. 代码: #include <cmath> #include <cstdio> #include <vector> #include <algorithm&

HDU 6617 Enveloping Convex(凸包+半平面交+二分)

首先对于这m个点维护出一个凸包M,那么问题就变成了判断凸包P进行放大缩小能不能包含凸包M.(凸包P可以进行中心对称变换再进行放大缩小,见题意) 如何判断合适的相似比呢,我们可以用二分去放大缩小凸包P的坐标,得到最小的相似比. 接下来就是如何判断是否包含.我们需要对凸包P上的每一条向量,在凸包M上找到这么一个点,使得这个点左侧的所有凸包M上的点都在向量的左侧,那么我们可以直接同时逆时针枚举,用一个变量维护凸包M上的点,因为是同逆时针,凸包M上的点至少有一个只会被遍历一次,那么复杂度可以证明为On,

【最小矩形面积覆盖:凸包+旋转卡壳】UVA 10173 Smallest Bounding Rectangle

[最小矩形面积覆盖:凸包+旋转卡壳]UVA 10173 Smallest Bounding Rectangle 题目链接:UVA 10173 Smallest Bounding Rectangle 题目大意 给你n个点,求能够覆盖所有点集的最小矩形面积. 笔者的第2道凸包题目,凸包 + 旋转卡壳,实现点集的最小矩形面积覆盖问题 ">=0"写成"<=0"坑了我一下午!QAQ 说一下思路 ①Graham's Scan法构建凸包,时间复杂度O(nlogn) ②

HDU 5251 矩形面积(二维凸包旋转卡壳最小矩形覆盖问题) --2015百度之星题目

B - 矩形面积 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description 小度熊有一个桌面,小度熊剪了很多矩形放在桌面上,小度熊想知道能把这些矩形包围起来的面积最小的矩形的面积是多少. Input 第一行一个正整数 T,代表测试数据组数(),接下来 T 组测试数据. 每组测试数据占若干行,第一行一个正整数 ,代表矩形的数量.接下来 N 行,每行 8

UVA 4728 Squares(凸包+旋转卡壳)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=17267 [思路] 凸包+旋转卡壳 求出凸包,用旋转卡壳算出凸包的直径即可. [代码] 1 #include<cstdio> 2 #include<vector> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 struct Pt { 8

BZOJ 1185 [HNOI2007]最小矩形覆盖:凸包 + 旋转卡壳

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1185 题意: 给出二维平面上的n个点,问你将所有点覆盖的最小矩形面积. 题解: 先找出凸包,然后旋转卡壳. 在旋转卡壳中有一个结论:最小覆盖矩形一定有一条边在凸包上. 所以先枚举矩形在凸包上的那条边(p[i],p[i+1]),然后利用单调性找出p[i]的对踵点p[u]. 至于左右两侧的切点p[l]和p[r],要利用它们连线在直线(p[i],p[i+1])上投影长度的单调性求出. 最后将

【模板】凸包向内推进求不严格的半平面交——poj3384

想不明白这题写严格的半平面交为什么会错 /* 凸包所有边向内推进r */ #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<vector> #include<algorithm> #include<queue> using namespace std; #define N 205 typedef double db;

【BZOJ-1502】月下柠檬树 计算几何 + 自适应Simpson积分

1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1017  Solved: 562[Submit][Status][Discuss] Description Input 文件的第1行包含一个整数n和一个实数alpha,表示柠檬树的层数和月亮的光线与地面夹角(单位为弧度).第2行包含n+1个实数h0,h1,h2,…,hn,表示树离地的高度和每层的高度.第3行包含n个实数r1,r2,…,rn,表示柠檬树每层下底面的