寻找凸包-graham扫描法

Graham扫描法通过维持一个关于候选点的栈S来解决凸包问题。输入集合Q中的每个点都被压栈一次,非CH(Q)中的点最终被弹出栈。当算法终止时,栈S仅包含CH(Q)中的顶点,以逆时针的顺序出现在边界上。该算法最核心的一点就是,逆时针方向遍历凸包时,应该在每个顶点处左转。

import java.util.*;
public class Graham
{
	static int MAX = 100015;
	static POINT[] point = new POINT[MAX];
	static int[] stack = new int[MAX];
	static int n;
	static int top;

	static class POINT
	{
		public double x,y;
		public POINT(int x,int y){
			this.x = x;
			this.y = y;
		}
	}
	
	//(p1-p0)x(p2-p0),判断两直线的相对位置
	static double xmul(POINT p1,POINT p2,POINT p0){
		return (p1.x-p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
	}
	
	static double distance(POINT p1,POINT p2){
		return (p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y);
	}
	
	static void swap(int i,int j){
		POINT tmp = point[i];
		point[i] = point[j];
		point[j] = tmp;
	}
	
	static void grahamscan(int n){
	//	if(n<2)
		int u = 0,i = 0;
		for(;i < n;i++)
			if((point[i].y < point[u].y)||(point[i].y == point[u].y && point[i].x<point[u].x ))
			 u = i;
		swap(u,0);
		Arrays.sort(point,0,n,new MyComp());
		for(i=0;i<3;i++) stack[i] = i; //point0 point1 point2入栈
		top = 2;
		for(i = 3;i < n;i++){
			while(xmul(point[i],point[stack[top]],point[stack[top-1]]) >= 0){//弹出非左转的点
				if(top == 0) break;
				top--;
			}
			stack[++top] = i;
		}
	}
	
	static class MyComp implements Comparator<POINT>
	{
		public int compare(POINT p1,POINT p2){
			double xm = xmul(p1,p2,point[0]);
			if(xm < 0) return 1;
			else if(xm == 0 && distance(p1,point[0])>distance(p2,point[0])) return 1;
			else return -1;
		}
	}

	static double area(int n){
		double area = 0;
		for(int i = 2;i <= n-1;i++){
			area += xmul(point[stack[i]],point[stack[i-1]],point[0]);
		}
		return Math.abs(area)/2;
	}
	
	static void input(){
		int x=0,y=0;
		Scanner cin = new Scanner(System.in);
		System.out.println("请输入点数");
		n = cin.nextInt();
		System.out.println("请输入x,y");
		for(int i = 0;i < n;i++){
			x = cin.nextInt();
			y = cin.nextInt();
			point[i] = new POINT(x,y);
		}
	}

	static void print(){
		System.out.println("凸包:");
		for(int i=0;i<=top;i++){
			System.out.print(stack[i]+"-");
		}
		System.out.println("0");
	}
	public static void main(String[] args){
		input();
		grahamscan(n);
		System.out.println("area: "+area(n));
		print();
	}
}
/*
请输入点数
4
请输入x,y
0 0
1 0
0 1
1 1
area: 1.0
0-1-2-3-0
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值