二维凸包 Graham 算法

三点以下的情况就不写了

Python:

import math

class Point( object ):

    def __init__( self, x, y ):
        self.x = x
        self.y = y

    def __cmp__( self, other ):
        if self.y < other.y:
            return -1
        elif self.y == other.y:
            if self.x < other.x:
                return -1
            elif self.x == other.x:
                return 0
            else:
                return 1
        else:
            return 1

    def __repr__( self ):
        return "(X: {x}, Y:{y})".format( x = self.x, y = self.y )

    @staticmethod
    def distance( p1, p2 ):
        return math.sqrt( ( p1.x - p2.x ) * ( p1.x - p2.x ) +                           ( p1.y - p2.y ) * ( p1.y - p2.y ) )

    @staticmethod
    def crossMultiply( p1, p2, p3 ):
        return ( p2.x - p1.x ) * ( p3.y - p1.y ) -                ( p2.y - p1.y ) * ( p3.x - p1.x )

points  = []
results = []

def graham():

    def find_start_point():
        res = Point( float( 'inf' ), float( 'inf' ) )
        for p in points:
            if res > p:
                res = p
        return res

    def _cmp( p1, p2 ):
        m = Point.crossMultiply( start_point, p1, p2 )
        if m < 0:
            return 1
        elif m == 0 and              Point.distance( start_point, p1 ) < Point.distance( start_point, p2 ):
            return 1
        else:
            return -1

    global points, results

    start_point = find_start_point()
    points.remove( start_point )
    points = sorted( points, _cmp )
    results.extend( [start_point, points.pop( 0 ), points.pop( 0 )] )

    for p in points:
        while ( Point.crossMultiply( results[-2], results[-1], p ) ) <= 0:
            results.pop()
        results.append( p )

    return results

if __name__ == "__main__":

    points.extend( [ Point( 30, 30 ),
                     Point( 50, 60 ),
                     Point( 60, 20 ),
                     Point( 70, 45 ),
                     Point( 86, 39 ),
                     Point( 112, 60 ),
                     Point( 200, 113 ),
                     Point( 250, 50 ),
                     Point( 300, 200 ),
                     Point( 130, 240 ),
                     Point( 76, 150 ),
                     Point( 47, 76 ),
                     Point( 36, 40 ),
                     Point( 33, 35 ) ] )
    res = graham()
    print res

Cpp:

#include <iostream>
#include <cmath>
#include <deque>
#include <algorithm>
using namespace std;

class Point
{
    public:

        Point( double x, double y )
        {
            this->x = x;
            this->y = y;
        }

        Point( const Point& other )
        {
            this->x = other.x;
            this->y = other.y;
        }

        bool operator < ( const Point& other ) const
        {
            if( this->y < other.y )
                return true;
            else if( this->y == other.y )
            {
                if( this->x < other.x )
                    return true;
                else
                    return false;
            }
            else
                return false;
        }

        bool operator == ( const Point& other ) const
        {
            return ( this->x == other.x ) && ( this->y == other.y );
        }

        friend ostream& operator << ( ostream& os, const Point& p )
        {
            os << "( X: " << p.x << ", " << "Y: " << p.y << " )" << endl;
            return os;
        }

        double x;
        double y;
};

Point start_point( 1 << 30, 1 << 30 );
deque< Point > points;
deque< Point > result;

double dist( const Point& p1, const Point& p2 )
{
    return sqrt( ( p1.x - p2.x ) * ( p1.x - p2.x ) + ( p1.y - p2.y ) * ( p1.y - p2.y ) );
}

double crossMultiply( const Point& p1, const Point& p2, const Point& p3 )
{
    return ( ( p2.x - p1.x ) * ( p3.y - p1.y ) - ( p2.y - p1.y ) * ( p3.x - p1.x ) );
}

bool cmp( const Point& p1, const Point& p2 )
{
    double m = crossMultiply( start_point, p1, p2 );
    if( m < 0 )
        return false;
    else if( m == 0 && ( dist( start_point, p1 ) < dist( start_point, p2 ) ) )
        return false;
    else
        return true;
}

void graham()
{
    for( int i = 0; i < points.size(); ++i )
        if( points[i] < start_point )
            start_point = points[i];

    for( deque< Point >::iterator iter = points.begin(); iter != points.end(); ++iter )
    {
        if( *iter == start_point )
        {
            points.erase( iter );
            break;
        }
    }

    sort( points.begin(), points.end(), cmp );
    result.push_back( start_point );
    result.push_back( points.front() );
    points.pop_front();
    result.push_back( points.front() );
    points.pop_front();

    for( int i = 0; i < points.size(); ++i )
    {
        while( crossMultiply( result[result.size() - 2], result[result.size() - 1], points[i] ) <= 0 )
            result.pop_back();
        result.push_back( points[i] );
    }
}

int main()
{
    points.push_back( Point( 30, 30 ) );
    points.push_back( Point( 50, 60 ) );
    points.push_back( Point( 60, 20 ) );
    points.push_back( Point( 70, 45 ) );
    points.push_back( Point( 86, 39 ) );
    points.push_back( Point( 112, 60 ) );
    points.push_back( Point( 200, 113 ) );
    points.push_back( Point( 250, 50 ) );
    points.push_back( Point( 300, 200 ) );
    points.push_back( Point( 130, 240 ) );
    points.push_back( Point( 76, 150 ) );
    points.push_back( Point( 47, 76 ) );
    points.push_back( Point( 36, 40 ) );
    points.push_back( Point( 33, 35 ) );

    graham();

    for( int i = 0; i < result.size(); ++i ){
        cout << result[i];
    }

    return 0;
}

Free Pascal:

program Graham;

type
  TPoint = record
    x : extended;
    y : extended;
  end;

var
  points : array[1..10000] of TPoint;
  result : array[1..10000] of TPoint;
  top : Integer;
  points_num : Integer;
  i : Integer;

procedure Swap( var a, b : TPoint ); inline;
var
  temp : TPoint;
begin
  temp := a;
  a := b;
  b := temp;
end;

procedure Init; inline;
var
  i : Integer;
begin
  readln( points_num );
  for i := 1 to points_num do
  begin
    with points[i] do
    begin
      readln( x, y );
    end
  end;
  for i := 1 to points_num do
  begin
    if ( points[i].y < points[1].y ) or
       ( points[i].y = points[1].y ) and
       ( points[i].x < points[1].x ) then
    begin
      Swap( points[1], points[i] );
    end
  end;
end;

function CrossMultiply( p1, p2, p3 : TPoint ) : extended; inline;
begin
  exit( ( p1.x - p3.x ) * ( p2.y - p3.y ) - ( p2.x - p3.x ) * ( p1.y - p3.y ) );
end;

function Distance( p1, p2 : TPoint ) : extended; inline;
begin
  exit( sqrt( ( p1.x - p2.x ) * ( p1.x - p2.x ) + ( p1.y - p2.y ) * ( p1.y - p2.y ) ) );
end;

procedure Sort( x, y : longint ); inline;
var
  xx, yy : longint;
  mid, temp : TPoint;
begin
  xx := x;
  yy := y;
  mid := points[ ( xx + yy ) shr 1];
  repeat
    while ( CrossMultiply( points[xx], mid, points[1] ) > 0 ) or
          ( CrossMultiply( points[xx], mid, points[1] ) = 0 ) and
          ( Distance( points[xx], points[1] ) < Distance( mid, points[1] ) ) do
    begin
      Inc( xx );
    end;
    while ( CrossMultiply( points[yy], mid, points[1] ) < 0 ) or
          ( CrossMultiply( points[yy], mid, points[1] ) = 0 ) and
          ( Distance( points[yy], points[1] ) > Distance( mid, points[1] ) ) do
    begin
      Dec( yy );
    end;
    if xx <= yy then
    begin
      Swap( points[xx], points[yy] );
      Inc( xx );
      Dec( yy );
    end;
  until xx > yy;
  if yy > x then Sort( x, yy );
  if xx < y then Sort( xx, y );
end;

procedure Push( i : longint ); inline;
begin
  inc( top );
  result[top] := points[i];
end;

procedure Graham; inline;
var
  i : Integer;
begin
  Sort( 2, points_num );
  top := 0;
  Push( 1 );
  Push( 2 );
  for i := 3 to points_num do
  begin
    while ( top > 1 ) and
          ( CrossMultiply( points[i], result[top], result[top - 1] ) >= 0 ) do
    begin
      dec( top );
    end;
    push( i );
  end;
end;

begin
  Init;
  Graham;
  for i := 1 to top do
  begin
    writeln( result[i].x, result[i].y );
  end;
  readln;
end.

还差 Scheme, Ada,SML 版本的没写。。。。我是不是有强迫症。。。。

不对,还有 JS 动漫版的~

时间: 2024-08-11 01:34:35

二维凸包 Graham 算法的相关文章

算法模板——计算几何2(二维凸包——Andrew算法)

实现功能:求出二维平面内一对散点的凸包(详见Codevs 1298) 很神奇的算法——先将各个点按坐标排序,然后像我们所知的那样一路左转,求出半边的凸包,然后反过来求另一半的凸包 我以前正是因为总抱着想一步到位的想法,所以每次都跪得很惨(HansBug:事实上这次是我这辈子第一次A掉凸包题) 然后别的没了,就是凸包的基本思想 (顺便输出凸包周长C和面积S,好评如潮哦) 1 type arr=array[0..100005] of longint; 2 var 3 i,j,k,l,m,n,m1,m

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

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

使用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

UVA 10652 Board Wrapping(二维凸包)

传送门 刘汝佳<算法竞赛入门经典>P272例题6包装木板 题意:有n块矩形木板,你的任务是用一个面积尽量小的凸多边形把它们抱起来,并计算出木板占整个包装面积的百分比. 输入:t组数据,每组先输入木板个数n,接下来n行,每行x,y,w,h,j.(x,y)是木板中心的坐标,w是宽,h是高,j是顺时针旋转的角度. 木板互不相交. 输出:对于每组数据,输出木板总面积占包装总面积的百分比,保留小数点后1位. 题解:典型的二维凸包问题,理解并调用模板即可. #include <math.h>

二维凸包模板

double cross(Point a,Point b) { return a.x*b.y-a.y*b.x; } double mul(Point p0,Point p1,Point p2) { return cross(p1-p0,p2-p0); } double dis(Point a) { return sqrt(a.x*a.x+a.y*a.y); } bool cmp(Point a,Point b) { if(dcmp(mul(p[0],a,b))==0) return dis(a-

Luogu 2742 二维凸包

Luogu 2742 二维凸包 使用 \(Andrew\) 算法.将点排序后分别求上下凸壳,用单调栈维护. 利用向量叉积来判断当前方向.若 \(v_1\times v_2<0\) ,说明 \(v_2\) 在 \(v_1\) 的右侧, \(<0\) 为左侧, \(=0\) 说明二者共线. 参考讲解. #include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #defin

[计算机图形学 with OpenGL] Chapter8 习题8.12 NLN二维线段裁剪算法实现

Nicholl-Lee-Nicholl二维线段裁剪算法相对于Cohen-Sutherland和Liang-Barsky算法来说,在求交点之前进行了线段端点相对于几个区域的判断,可以确切的知道要求交点的边的信息. 此方法只在二维空间裁剪时使用,C-S和L-B裁剪方法则可应用到三维空间. 算法步骤: 1 先使用C-S裁剪算法的区域码判断方法,去除一部分在裁剪区域外面的线段.显示在完全在裁剪区域内的线段.其他不能判断的情况,采用NLN算法进行裁剪. 2 p1和p2若有一点在区域内,必要时交换端点以确保

二维凸包

二维凸包模板 p[1010]//输入的点集,res[1010]//输出的点集 int n;//点的个数 int cmp(Point a,Point b)//先对x坐标排序,在比较y坐标 { if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int ConvexHull()//返回凸包顶点数 { sort(p,p+n,cmp); int m=0; for(int i=0;i<=n-1;i++) { while(m>1&&Cr

二维凸包的板子

二维凸包的板子 感觉没什么可说的,码风抄的孔老师的. #include <cstdio> #include <algorithm> #include <cmath> const int N=1e4+10; #define Point Vector const double eps=1e-8; bool cmp(double a,double b){return fabs(a-b)<eps;} struct Vector { double x,y; Vector()