凸包(Convex Hull)问题的Gift-wrapping算法

一、凸包问题是什么

假设平面上有p0~p12共13个点,过某些点作一个多边形,使这个多边形能把所有点都“包”起来。当这个多边形是凸多边形的时候,我们就叫它“凸包”。

        

 二、Gift-wrapping算法实现

        1.算法概述

        顾名思义,Gift-wrapping算法即将点集从最左下点开始,像礼物包装一样,通过一个方向,将最外层点加入凸包的点集,最后回到出发点,获取的完整点集即为该点集的凸包

        2.代码实现

        要注意,当三个点共线时,应选择距离当前点距离最大的点加入凸包点集

public static Set<Point> convexHull(Set<Point> points) {
    	ArrayList<Point> pointlist=new ArrayList<>();
    	Set<Point> hashpoint=new HashSet<>();
    	pointlist.addAll(points);
    	if(pointlist.size()<=3)	return points;
    	Point stpoint=pointlist.get(0);
    	for(Point p:points)
    	{
    		if(p.x()<stpoint.x()||(p.x()==stpoint.x()&&p.y()<stpoint.y()))
    		{
    			stpoint=p;
    		}
    	}
    	Point fp=stpoint,tmp=null,reg=null;
    	double current=0,angle=0,anglemin=360,tmpdis2=0,tmpdis1=0;
    	int i=0;
    	do
    	{
    		i++;
    		tmpdis2=0;tmpdis1=0;
    		if(i==3) points.add(stpoint);
    		for(Point p1:points)
    		{
    			angle=calculateBearingToPoint(current,(int)fp.x(),(int)fp.y(),(int)p1.x(),(int)p1.y());
    			if(angle<anglemin)
    			{
    				anglemin=angle;
    				reg=p1;
    				tmp=p1;
    			}
    			if(angle==anglemin)
    			{
    				tmpdis1=(p1.x()-reg.x())*(p1.x()-reg.x())+(p1.y()-reg.y())*(p1.y()-reg.y());
    				tmpdis2=(p1.x()-fp.x())*(p1.x()-fp.x())+(p1.y()-fp.y())*(p1.y()-fp.y());
    				if(tmpdis1<tmpdis2)
    				{
    					reg=p1;
    					tmp=p1;   					
    				}
    			}
    		}   		
    			current=0;
    			anglemin=360;
    			fp=tmp;   			
    			hashpoint.add(tmp);
    			points.remove(tmp);
    		
    	}while(tmp!=stpoint||i<=pointlist.size());
    	return hashpoint;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是 Graham-Scan 算法的 C++ 实现,用于求解问题: ```cpp #include <bits/stdc++.h> using namespace std; struct Point { int x, y; }; // 按照 x 坐标从小到大排序,若 x 坐标相等,则按照 y 坐标从小到大排序。 bool cmp(Point a, Point b) { if (a.x == b.x) return a.y < b.y; return a.x < b.x; } // 计算叉积。 int cross(Point a, Point b, Point c) { return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); } // Graham-Scan 算法求解。 vector<Point> grahamScan(vector<Point> &points) { int n = points.size(); if (n <= 1) return points; sort(points.begin(), points.end(), cmp); vector<Point> hull(2 * n); int k = 0; // 构建下壳。 for (int i = 0; i < n; ++i) { while (k >= 2 && cross(hull[k - 2], hull[k - 1], points[i]) <= 0) k--; hull[k++] = points[i]; } // 构建上壳。 for (int i = n - 2, t = k + 1; i >= 0; --i) { while (k >= t && cross(hull[k - 2], hull[k - 1], points[i]) <= 0) k--; hull[k++] = points[i]; } // 去除重复点。 hull.resize(k - 1); return hull; } int main() { // 测试数据。 vector<Point> points = {{0, 3}, {1, 1}, {2, 2}, {4, 4}, {0, 0}, {1, 2}, {3, 1}, {3, 3}}; vector<Point> hull = grahamScan(points); // 输出的顶点。 for (int i = 0; i < hull.size(); ++i) { cout << "(" << hull[i].x << ", " << hull[i].y << ")" << endl; } return 0; } ``` 注意点: 1. 为了方便起见,我直接使用了 C++11 的新特性,使用 vector 存储点集,如果你使用的是较老的编译器,可以使用数组代替 vector。 2. 实现中为了方便起见,我使用了三个点 $A(a_x,a_y)$、$B(b_x,b_y)$、$C(c_x,c_y)$ 的叉积 $cross(A,B,C)$ 表示向量 $\vec{AB}$ 和 $\vec{AC}$ 的叉积。当叉积 $cross(A,B,C)>0$ 时,表示 $\vec{AB}$ 在 $\vec{AC}$ 的逆时针方向;当叉积 $cross(A,B,C)<0$ 时,表示 $\vec{AB}$ 在 $\vec{AC}$ 的顺时针方向;当叉积 $cross(A,B,C)=0$ 时,表示 $\vec{AB}$ 和 $\vec{AC}$ 共线。 3. 为了避免精度误差,最好使用整数类型存储坐标,如 int 类型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值