凸包——Graham扫描法和Andrew算法

凸包:能围住所有给出的点的面积最小的多边形(个人理解)

Graham:选取y值最小的点,将其它点极角排序,依次把1~n号点加入栈中,判断当前点、栈顶、栈顶下面那个点三者的关系(嘻嘻),一直这样做就好了

判断用叉积,也就是如下图的要判掉(top--)

其实上图是不对的哦,你有没有反应过来呢~按极角排序后不会有这种情况哦,肯定是先连a[i],再连s[top]的

具体实现看代码吧~

#include<cstdio>
#include<cmath>
#include<algorithm>
#define sqr(x) (x)*(x)
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define per(i,x,y) for (int i=(x);i>=(y);i--)
typedef double DBD;
using namespace std;
const int N=100010;
struct point{int x,y;}a[N],s[N],b[N];
int n,top;
int read() {int d=0,f=1; char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1; c=getchar();} while (c>=‘0‘&&c<=‘9‘) d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;}
DBD dis(int x,int xx,int y,int yy){return sqrt(sqr(x-xx)+sqr(y-yy));}
bool cross(point x,point y,point z){return (x.x-z.x)*(y.y-z.y)-(y.x-z.x)*(x.y-z.y)>=0;}
bool cmp(point A,point B){return (A.x-a[1].x)*(B.y-a[1].y)-(B.x-a[1].x)*(A.y-a[1].y)>=0;}
int main()
{
    //judge();
    n=read();
    int p=0; a[0].y=1e9;
    rep(i,1,n)
    {
        a[i].x=read(); a[i].y=read();
        if (a[i].y<a[p].y||a[i].y==a[p].y&&a[i].x<a[p].x) p=i;
    }
    swap(a[1],a[p]);
    sort(a+2,a+1+n,cmp);
    s[1]=a[1]; s[2]=a[2]; top=2;
    rep(i,3,n)
    {
        while (top>=2&&cross(a[i],s[top],s[top-1])) top--;
        s[++top]=a[i];
    }
    DBD ans=0;
    for (int i=1;i<top;i++) ans+=dis(s[i].x,s[i+1].x,s[i].y,s[i+1].y);
    ans+=dis(s[1].x,s[top].x,s[1].y,s[top].y);
    printf("%.1lf",ans);
    return 0;
}

Graham

Andrew:

据说比Graham更快更稳定,但我不是很懂。。。

具体过程(哪里具体了。。。):将所有点以x为第一关键字,y为第二关键字排序,分别求出上下凸壳,求的时候一样的判法,就好了

#include<cstdio>
#include<cmath>
#include<algorithm>
#define sqr(x) (x)*(x)
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define per(i,x,y) for (int i=(x);i>=(y);i--)
typedef double DBD;
using namespace std;
const int N=100010;
struct point{int x,y;}a[N],s[N];
int n,top;
int read() {int d=0,f=1; char c=getchar(); while (c<‘0‘||c>‘9‘) {if (c==‘-‘) f=-1; c=getchar();} while (c>=‘0‘&&c<=‘9‘) d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;}
DBD dis(int x,int xx,int y,int yy){return sqrt(sqr(x-xx)+sqr(y-yy));}
DBD cross(point x,point y,point z){return (x.x-z.x)*(y.y-z.y)-(y.x-z.x)*(x.y-z.y);}
bool cmp(point a,point b){return a.x<b.x||a.x==b.x&&a.y<b.y;}
int main()
{
    n=read();
    rep(i,1,n) a[i].x=read(),a[i].y=read();
    sort(a+1,a+1+n,cmp);
    rep(i,1,n)
    {
        while (top>1&&cross(a[i],s[top],s[top-1])>=0) top--;
        s[++top]=a[i];
    }
    int k=top;
    per(i,n-1,1)
    {
        while (top>k&&cross(a[i],s[top],s[top-1])>=0) top--;
        s[++top]=a[i];
    }
    DBD ans=0;
    rep(i,1,top-1) ans+=dis(s[i].x,s[i+1].x,s[i].y,s[i+1].y);
    ans+=dis(s[1].x,s[top].x,s[1].y,s[top].y);
    printf("%.1lf",ans);
    return 0;
}

Andrew

可能你会疑问:为什么第n个点一定在凸包上呢?当然了,因为它的x最大,即使有和它x一样的,它的y更大,yy一下就脑补出来了

时间: 2024-10-29 22:37:41

凸包——Graham扫描法和Andrew算法的相关文章

【POJ 2187】 Beauty Contest (凸包-Graham扫描算法)

[POJ 2187] Beauty Contest (凸包-Graham扫描算法) 找平面最远点对 数据很大 用暴力会T..我感觉-- 扫描出个凸包 然后枚举凸包上的点即可 没坑 int也可过 注意重边跟共线就行 代码下附赠几组数据 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include

计算几何 二维凸包问题 Andrew算法

凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把所有点排序,按照第一关键字x第二关键字y从小到大排序,删除重复点后得到点序列P1...Pn. 1)把P1,P2放入凸包中,凸包中的点使用栈存储 2)从p3开始,当下一个点在凸包当前前进方向(即直线p1p2)左边的时候继续: 3)否则依次删除最近加入凸包的点,直到新点在左边. 如图,新点P18在当前前进方向P10P15的右边(使用叉积判断),因此需要从凸包上删除点P15和P10

POJ 2187 旋转卡壳 + 水平序 Graham 扫描算法

水平序 Graham 扫描算法: 计算二维凸包的时候可以用到,Graham 扫描算法有水平序和极角序两种. 极角序算法能一次确定整个凸包, 但是计算极角需要用到三角函数,速度较慢,精度较差,特殊情况较多. 水平序算法需要扫描两次,但排序简单,讨论简单,不易出错. [算法流程] 1.对顶点按x为第一关键字,y为第二关键字进行排序. 2.准备一个空栈,并将前两个点压入栈. 3.对于每一个顶点A,只要栈顶中还至少两个顶点,记栈顶为T,栈中第二个为U. 若UT(向量) * TA(向量) <= 0, 则将

使用Apriori算法和FP-growth算法进行关联分析(Python版)

===================================================================== <机器学习实战>系列博客是博主阅读<机器学习实战>这本书的笔记也包含一些其他python实现的机器学习算法 算法实现均采用python github 源码同步:https://github.com/Thinkgamer/Machine-Learning-With-Python ==================================

时空权衡之输入增强 ----字符串匹配算法Horspool算法和Boyer-Moore算法

在算法设计的时空权衡设计技术中,对问题的部分或者全部输入做预处理,对获得的额外信息进行存储,以加速后面问题的求解的思想,我们称作输入增强. 其中字符串匹配算法Horspool算法和Boyer-Moore算法就是输入增强的例子. 首先了解一下字符串匹配的概念.我们把在一个较长的n个字符的串中,寻找一个给定的m个字符的串的问题,称为字符串匹配问题.较长的串称为text,而需要寻找的串称为pattern. 字符串匹配问题的蛮力算法很好理解:我们把pattern与text第一个字符对齐,从左往右比较pa

使用Apriori算法和FP-growth算法进行关联分析

系列文章:<机器学习>学习笔记 最近看了<机器学习实战>中的第11章(使用Apriori算法进行关联分析)和第12章(使用FP-growth算法来高效发现频繁项集).正如章节标题所示,这两章讲了无监督机器学习方法中的关联分析问题.关联分析可以用于回答"哪些商品经常被同时购买?"之类的问题.书中举了一些关联分析的例子: 通过查看哪些商品经常在一起购买,可以帮助商店了解用户的购买行为.这种从数据海洋中抽取的知识可以用于商品定价.市场促销.存活管理等环节. 在美国国会

凸包-Graham扫描法

RT,Graham扫描法求凸包分为3步: 1.找到y最小的点 2.以y最小的点O为原点,求其余所有点相对O的极角并按极角从小到大排序 3.对于排序后的点集,配合栈,完成Graham扫描. ConvexHull.py #coding=utf-8 import math import numpy import pylab as pl #画原始图 def drawGraph(x,y): pl.title("The Convex Hull") pl.xlabel("x axis&qu

最短路径Dijkstra算法和Floyd算法整理、

转载自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最短路径—Dijkstra算法和Floyd算法 Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹

Dijkstra算法和Floyed算法

写的比较好的三篇文章 Floyed算法 最短路径-Dijkstra算法和Floyed算法 最短路径之Dijkstra算法和Floyed算法 哈哈,他山之石,可以攻玉 自己有心得,慢慢补充