凸包-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")
    pl.ylabel("y axis")
    pl.plot(x,y,'ro')
#画凸包
def drawCH(x,y):
    #pl.plot(x,y1,label='DP',linewidth=4,color='red')
    pl.plot(x,y,color='blue',linewidth=2)
    pl.plot(x[-1],y[-1],x[0],y[0])
    lastx=[x[-1],x[0]]
    lasty=[y[-1],y[0]]
    pl.plot(lastx,lasty,color='blue',linewidth=2)
#存点的矩阵,每行一个点,列0->x坐标,列1->y坐标,列2->代表极角
def matrix(rows,cols):
    cols=3
    mat = [[0 for col in range (cols)]
              for row in range(rows)]
    return mat
#返回叉积
def crossMut(stack,p3):
    p2=stack[-1]
    p1=stack[-2]
    vx,vy=(p2[0]-p1[0],p2[1]-p1[1])
    wx,wy=(p3[0]-p1[0],p3[1]-p1[1])
    return (vx*wy-vy*wx)
#Graham扫描法O(nlogn),mat是经过极角排序的点集
def GrahamScan(mat):
    #print mat
    points=len(mat) #点数
    """
    for k in range(points):
        print mat[k][0],mat[k][1],mat[k][2]
    """
    stack=[]
    stack.append((mat[0][0],mat[0][1])) #push p0
    stack.append((mat[1][0],mat[1][1])) #push p1
    stack.append((mat[2][0],mat[2][1])) #push p2
    for i in range(3,points):
        #print stack
        p3=(mat[i][0],mat[i][1])
        while crossMut(stack,p3)<0:stack.pop()
        stack.append(p3)
    return stack

#main
max_num = 30 #最大点数
x=100*numpy.random.random(max_num)#[0,100)
y=100*numpy.random.random(max_num)
drawGraph(x,y)
mat = matrix(max_num,3) #最多能存50个点
minn = 300
for i in range(max_num):    #存点集
    mat[i][0],mat[i][1]=x[i],y[i]
    if y[i]<minn: #(x[tmp],y[tmp])-->y轴最低坐标
        minn=y[i]
        tmp = i
d = {}  #利用字典的排序
for i in range(max_num):    #计算极角
    if (mat[i][0],mat[i][1])==(x[tmp],y[tmp]):mat[i][2]=0
    else:mat[i][2]=math.atan2((mat[i][1]-y[tmp]),(mat[i][0]-x[tmp]))
    d[(mat[i][0],mat[i][1])]=mat[i][2]
lst=sorted(d.items(),key=lambda e:e[1]) #按极角由小到大排序
for i in range(max_num):    #装排序后的矩阵
    ((x,y),eth0)=lst[i]
    mat[i][0],mat[i][1],mat[i][2]=x,y,eth0
stack=GrahamScan(mat)
x,y=[],[]
for z in stack:
    x.append(z[0])
    y.append(z[1])
drawCH(x,y)
pl.show()

ps: Graham的复杂度为O(nlogn)

求平面最远的点对可转化为先求凸包+旋转卡壳(可以证明,平面上最远的点对一定都在凸包上。)

时间: 2024-10-12 13:02:35

凸包-Graham扫描法的相关文章

[hdu contest 2019-07-29] Azshara&#39;s deep sea 计算几何 动态规划 区间dp 凸包 graham扫描法

今天hdu的比赛的第一题,凸包+区间dp. 给出n个点m个圆,n<400,m<100,要求找出凸包然后给凸包上的点连线,连线的两个点不能(在凸包上)相邻,连线不能与圆相交或相切,连线不能相交但是可以有公共端点. 首先找出凸包,然后把n*n条边和m个圆算点到直线距离验证一下边是否与圆相交存到e[n][n]里. 然后显然是一个dp,但是我开始看错题目了以为不能有公共端点,能有公共端点的情况考虑一下像一个找三角形的过程,就是区间dp. 区间dp有一点妙的地方是最大区间范围是凸包点数而不用+1,因为连

poj1113Wall 求凸包周长 Graham扫描法

#include<iostream> #include<algorithm> #include<cmath> using namespace std; typedef pair<int ,int > ll; ll num,dot[1010]; int i; const double pi=3.1415926535898; ll operator -(ll a,ll b) { return make_pair(a.first-b.first,a.second-

计算几何 : 凸包学习笔记 --- Graham 扫描法

凸包 (只针对二维平面内的凸包) 一.定义 简单的说,在一个二维平面内有n个点的集合S,现在要你选择一个点集C,C中的点构成一个凸多边形G,使得S集合的所有点要么在G内,要么在G上,并且保证这个凸多边形的面积最小,我们要求的就是这个C集合. 二.算法 求凸包的算法很多,常用的有两种: 1.  Graham扫描法,运行时间为O(nlgn). 2.  Jarvis步进法,运行时间为O(nh),h为凸包中的顶点数. 这里主要讨论第一种算法:Graham扫描法 Graham扫描法: 基本思想:使用一个栈

(模板)poj1113(graham扫描法求凸包)

题目链接:https://vjudge.net/problem/POJ-1113 题意:简化下题意即求凸包的周长+2×PI×r. 思路:用graham求凸包,模板是kuangbin的. AC code: #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int maxn=1005; const double PI=

HDU 5928 DP 凸包graham

给出点集,和不大于L长的绳子,问能包裹住的最多点数. 考虑每个点都作为左下角的起点跑一遍极角序求凸包,求的过程中用DP记录当前以j为当前末端为结束的的最小长度,其中一维作为背包的是凸包内侧点的数量.也就是 dp[j][k]代表当前链末端为j,其内部点包括边界数量为k的最小长度.这样最后得到的一定是最优的凸包. 然后就是要注意要dp[j][k]的值不能超过L,每跑一次凸包,求个最大的点数量就好了. 和DP结合的计算几何题,主要考虑DP怎么搞 /** @Date : 2017-09-27 17:27

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

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

凸包(Convex Hull)构造算法——Graham扫描法

凸包(Convex Hull) 在图形学中,凸包是一个非常重要的概念.简明的说,在平面中给出N个点,找出一个由其中某些点作为顶点组成的凸多边形,恰好能围住所有的N个点. 这十分像是在一块木板上钉了N个钉子,然后用一根绷紧的橡皮筋它们都圈起来,这根橡皮筋的形状就是所谓的凸包. 计算凸包的一个著名算法是Graham Scan法,它的时间复杂度与所采用的排序算法时间复杂度相同,通常采用线性对数算法,因此为\( O\left(N\mathrm{log}\left(N\right)\right) \).

[POJ1113&amp;POJ1696]凸包卷包裹算法和Graham扫描法应用各一例

凸包的算法比较形象好理解 代码写起来也比较短 所以考前看一遍应该就没什么问题了..>_< POJ1113 刚开始并没有理解为什么要用凸包,心想如果贴着城堡走不是更好吗? 突然发现题目中有要求在满足把所有点包括在内的情况下周长最短...这不就是凸包的性质吗? 而且显然如果城堡是凹的话,往里面绕一圈肯定会使周长增加... 然后可以从简单的三角形四边形推广出去,发现每个拐角-左右各90度之后所有的加和为180度 也就是在城堡周长的基础上再加一个半径为L的圆周长即是所求答案. 上次的模板写错了...应

使用Graham扫描法求二维凸包的一个程序

1 #include "includeall.h" 2 #include "Link.class.h" 3 4 int RightOrLeft(float x1,float y1,float x2,float y2,float x3,float y3)//判断第三个点在前两个点连成的直线的哪个位置,-1 左边,0,直线上,1 右边 5 { 6 float X=(y3-y1)*(x2-x1)/(y2-y1)+x1; 7 if(X<x3) 8 { 9 return