Graham_Scan解决凸包问题

人类对于未知的事物,第一反应总是恐惧的。


大一在ACM做题的时候,遇到过一个凸包问题。然后看其他同学下了个模板,朦朦胧胧的给过了,就感觉这么难!网上都有模板了,自己看来是写不出这种模板的。


现在看了算法导论,想想当时的自己,已经哭晕在厕所。


Graham_Scan算法,主要是对于数学的叉积的理论的熟悉比较重要,向量p1p0 ( x1 , y1 ) 叉积 p2p0( x2 , y2 )  : ( x1 * y2 ) - ( y1 * x2 )。结果为正的,则表示p2p0向量在p1p0向量的左侧。


而在Graham_Scan算法里,因为要将所有的点都包起来,所以B点距离下一个点C,则B点之前的A点与C点构成的向量与B点与C点构成的向量的叉积肯定是要负的,如果是正的,则要将B点排除出凸包边上点集合。


public class Graham_Scan {
	
	public void Scan(Node[] ns){
		
		Node[] Q = new Node[ns.length];//保存凸包边上的点;
		int top = 0;//保存 栈顶位置
		
		int k = 0 ;
		
		for(int i = 1 ; i < ns.length ; i ++)
			if (ns[i].y < ns[k].y || (ns[i].y == ns[k].y && ns[i].x < ns[k].x)) 
				k = i;
		
		Node tmp = ns[k];
		ns[k] = ns[0];
		ns[0] = tmp;
		
		
		for(int i = 1 ; i < ns.length ; i ++){
			
			k = i;
			
			for(int j = i + 1 ; j < ns.length ; j ++){
				
				if ( (cross(ns[j], ns[k], ns[0]) > 0 ) || ( cross(ns[j], ns[k], ns[0]) == 0 && dist(ns[j], ns[0]) < dist(ns[k], ns[0]) ) ) {
					k = j;
				}
				
			}
			
			tmp = ns[k];
			ns[k] = ns[i];
			ns[i] = tmp;
			
		}
		
		top = -1;
		Q[++top] = ns[0];
		Q[++top] = ns[1];
		Q[++top] = ns[2];
		
		for(int i = 3; i < ns.length ; i ++){
			
			while (cross(ns[i], Q[top], Q[top - 1]) > 0) {//
				top --;
			}
			
			Q[++top] = ns[i];
			
		}
		
		
	}
	
	private int cross(Node n1, Node n2, Node n0){
		
		int sign = (n1.x - n0.x)*(n2.y - n0.y) - (n2.x - n0.x)*(n2.y - n0.y);
		
		return sign;
		
	}
	
	private double dist(Node n1 , Node n2){
		
		return Math.sqrt((n1.x - n2.x)*(n1.x - n2.x) + (n1.y - n2.y)*(n1.y - n2.y));
		
	}
	
	private class Node{
		
		private int x;
		private int y;
		
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值