最小凸型集问题:礼品包装盒算法

最小凸型集问题如下:现有一个点集Set<Point> S0,其中Point类是二维点的实现,拥有成员变量double x和double y。若集合S1定义为包围点集S0所有点的最小凸多边形则集合S=S0∩S1定义为集合S0的最小凸型集。

这个问题的一个解决方法是礼品包装盒算法,先附上Java代码:

public static Set<Point> convexHull(Set<Point> points) {
        Point p[]=new Point[points.size()];
    	points.toArray(p);
        ArrayList<Point> pList=new ArrayList<Point>();
        for(int i=0;i<p.length;i++)
        	pList.add(p[i]);        
        Collections.sort(pList);
        Set<Point> rs=new HashSet<Point>();
        int tmp=0;
        double currentDegree=0,curminDegree=360,degree=0;
        Point p0=pList.get(0),p1=new Point(0,0);
        do
        {
        	for(int j=0;j<pList.size();j++)
        	{
        		if(tmp==j) continue;
        		p1=pList.get(j);
        		degree=calculateBearingToPoint(currentDegree,p0.x(),p0.y(),p1.x(),p1.y());
        		if(degree<curminDegree)
        		{
        			curminDegree=degree;
        			tmp=j;
        		}
        	}
        	currentDegree+=curminDegree;
        	curminDegree=360;
        	if(currentDegree>=360)
        		currentDegree-=360;
        	p0=pList.get(tmp);
        	rs.add(p0);
        	System.out.println(p0.x()+" "+p0.y());
        }while(tmp!=0);
        return rs;
    }
	public static double calculateBearingToPoint(double currentBearing, double currentX, double currentY, double targetX,
			double targetY) {
		double vectorX = targetX - currentX;
		double vectorY = targetY - currentY;
		double degree = 180 * Math.acos( vectorY / Math.sqrt(vectorX * vectorX + vectorY * vectorY)) / Math.PI;
		if (vectorX < 0)
			degree = 360 - degree;
		double cbtp = degree - currentBearing;
		if (cbtp < 0)
			return 360 + degree;
		else
			return cbtp;
	}

礼品包装盒算法基于如下定理:对于一个二维平面内的任意一点z,设集合S0的最小凸型集为S,z∈S的充要条件是该二维平面存在一组正交基(L1,L2)且若设X(z)和Y(z)定义为点z以(L1,L2)为基底对应的两个坐标值,对于平面内任意一点z0有X(z)≤X(z0)或Y(z)≤Y(z0)成立。(这一定理由反证法不难证明)

因此礼品包装盒算法通过先加入所有点中x值最小的点(Point类保存二维点所用的x,y本身便是以0,1和1,0两向量为正交基获得的坐标值,因此由上述定理x最小的点一定在最小凸点集内),再以这个点为基准点,从基准点从(0,1)方向开始顺时针旋转(如下图所示,图片所示是从p0以方向0,-1开始旋转,但由于我们选择的初始基准点是x最小的点,从0,-1方向和0,1方向开始不会有区别),找到剩余点中旋转角最小的点,加入该点并以该点为基准点重复这一过程,直至再次搜索到初始的基准点,此时便获得了集合S0的最小凸点集S。

上述代码中calculateBearingToPoint方法实现了从初始角度currentBearing,初始点(currentX,currentY)到目标点(targetX,targetY)的旋转角,因此只需按照算法反复调用这个方法即实现了最小凸点集问题的求解。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值