分治法求二维凸包问题java

https://blog.csdn.net/bone_ace/article/details/46239187
见解法2。
有一点需要说明的是,如果有多个到直线p1 pn的距离都最大的点,找pmax使的∠pmax p1 pn最大
下面为java代码

package fd;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;





class MyComparator implements Comparator<Point>{
    @Override
    public int compare(Point o1, Point o2) {
        
        if(o1.getX() < o2.getX()) 
        { 
          return -1;
        }
        
        else if(o1.getX() > o2.getX()) 
        {
          return 1;
        }
        
        
        else 
        {
        	if(o1.getY() < o2.getY()) 
        	{ 
                return -1;
            }
        	
        	else if(o1.getY() > o2.getY()) 
            {
                return 1;
            }
            
        	else 
            {
               return 0;
            }
        }
    }
} 


public class Main {

	
	public static double abscissa(Point q1,Point q2,Point q3)
	{
		//q1,q2,q3是p0,pn_1,p3
		//这里所求的是p3落在p0,pn_1直线上时,p3'横坐标
		//上包横坐标越小,角越大
		//下包横坐标越大,角越大
		
		//q1q2直线:ax+by=c;
		double a=q2.getY()-q1.getY();
		double b=q1.getX()-q2.getX();
		double c=q1.getX()*q2.getY()-q1.getY()*q2.getX();
		//过q3做上面的垂线:bx-ay=c1,带入q3求c1
		double c1=b*q3.getX()-a*q3.getY();
		//两直线联立求交点,即p3落下来的点
		double x=(a*c+b*c1)/(a*a+b*b);
		double y=(b*c-a*c1)/(a*a+b*b);
		
		
		return x;
		
		
	}
	
	
	
	
	public static double area(Point q1,Point q2,Point q3)
	{
		double x=q1.getX()*q2.getY()+q3.getX()*q1.getY()+q2.getX()*q3.getY()
				-q3.getX()*q2.getY()-q2.getX()*q1.getY()-q1.getX()*q3.getY();
		
		return x/2;
	}
	
	
	public static ArrayList<Point>   hull(ArrayList<Point> points,Point p0,Point pn_1,int is)
	{//is==1是上包,is==0是下包
		
		//找Pmax
		
		double max=0;
		int index=-1;//最大的指标
		for(int i=0;i<points.size();i++)
		{
			double value=area(p0,pn_1,points.get(i));
			if(value>max)
			{
				max=value;
				index=i;
			}
			else if(value==max)
			{	//points.get(index);原来的那个
				//points.get(i);当前的这个
				
				//对于上包来说
				//当前这个角如果更小,也就是横坐标更大
				
				//对于下包来说
				//当前这个角如果更大,也就是横坐标更大
			//这个地方应该是唯一上下包唯一不同的地方
				if(is==1)
				{	
					if(abscissa(p0,pn_1,points.get(i))<abscissa(p0,pn_1,points.get(index)))
					{
						index=i;
					}
				}
				
				else
				{	
					if(abscissa(p0,pn_1,points.get(i))>abscissa(p0,pn_1,points.get(index)))
					{
						index=i;
					}
				}
					
					
			}
			
		}
		if(index==-1)//找不到Pmax,只返回这两个点
		{
			ArrayList<Point> answer_up=new ArrayList<Point>();
			answer_up.add(p0);
			answer_up.add(pn_1);
			return answer_up;
		}
		
		
		
		else
		{
			
			
			
			Point pmax=points.get(index);
			
			
			ArrayList<Point> points1=new ArrayList<Point>();
			ArrayList<Point> points2=new ArrayList<Point>();
			
			for(int i=0;i<points.size();i++)
			{
				if(area(p0,pmax,points.get(i))>0)
				{
				points1.add(points.get(i));	
				}
				
				if(area(pmax,pn_1,points.get(i))>0)
				{
				points2.add(points.get(i));	
				}
			}	
			
			
			
			ArrayList<Point> answer1=hull(points1,p0,pmax,is);
			
			
			ArrayList<Point> answer2=hull(points2,pmax,pn_1,is);
			
			//合并................................................
			
			answer2.remove(0);//不考虑重复的节点pmax
			answer1.addAll(answer2);
			return answer1;
		}
		
		
	}
	
	
	
	
	
	
	
	
	
	public static ArrayList<Point>   lowerhull(ArrayList<Point> points,Point pn_1,Point p0)
	{
		//找Pmax
		
		double max=0;
		int index=-1;//最大的指标
		for(int i=0;i<points.size();i++)
		{
			double value=area(pn_1,p0,points.get(i));
			if(value>max)
			{
				max=value;
				index=i;
			}
			else if(value==max)
			{//对于下包来说
				//当前这个角如果更大,也就是横坐标更大
				//points.get(index);原来的那个
				//points.get(i);当前的这个
			//这个地方应该是唯一上下包唯一不同的地方
				if(abscissa(pn_1,p0,points.get(i))>abscissa(pn_1,p0,points.get(index)))
				{
					index=i;
				}
			}
			
		}
		if(index==-1)//找不到Pmax,只返回这两个点
		{
			ArrayList<Point> answer_low=new ArrayList<Point>();
			answer_low.add(pn_1);
			answer_low.add(p0);
			return answer_low;
		}
		
		
		
		else
		{
			
			
			
			Point pmax=points.get(index);
			
			
			ArrayList<Point> points1=new ArrayList<Point>();
			ArrayList<Point> points2=new ArrayList<Point>();
			
			for(int i=0;i<points.size();i++)
			{
				if(area(pn_1,pmax,points.get(i))>0)
				{
				points1.add(points.get(i));	
				}
				
				if(area(pmax,p0,points.get(i))>0)
				{
				points2.add(points.get(i));	
				}
			}	
			
			
			
			ArrayList<Point> answer_low1=lowerhull(points1,pn_1,pmax);
			
			
			ArrayList<Point> answer_low2=lowerhull(points2,pmax,p0);
			
			//合并................................................
			
			answer_low2.remove(0);//不考虑重复的节点pmax
			answer_low1.addAll(answer_low2);
			return answer_low1;
		}
		
		
	}
	
	
	
	public static ArrayList<Point> solve(ArrayList<Point> points)
	{
		ArrayList<Point>answer=new ArrayList<Point>();
		//以下按逆时针方向
		Point p0=points.get(0);
		Point pn_1=points.get(points.size()-1);
		ArrayList<Point>up=new ArrayList<Point>();
		ArrayList<Point>down=new ArrayList<Point>();
		
		
		for(int i=1;i<points.size()-1;i++)
			{
				if(area(p0,pn_1,points.get(i))>0)
				{
				up.add(points.get(i));	
				}
				
				else if(area(p0,pn_1,points.get(i))<0)
				{
				down.add(points.get(i));	
				}
			}	
		
		
		
		
		
		answer.addAll(hull(up, p0, pn_1,1));//加入上包
		
		ArrayList<Point>low=hull(down, pn_1, p0,0);//保存下包
		low.remove(0);//除掉pn_1
		low.remove(low.size()-1);//除掉p0
		answer.addAll(low);//加入下包
		
		return answer;
	}
	
	
	
	
	public static void main(String[] args) {
		
		Point P[]=new Point[10];

		for(int i=0;i<10;i++)
		{
			P[i]=new Point((int)(Math.random()*100),(int)(Math.random()*100));
	
		}
		
		
		
		
		
		Arrays.sort(P,new MyComparator());
		
		ArrayList<Point> points=new ArrayList<Point>();//下面用ArrayList,是因为有些元素要删掉
		
		Collections.addAll(points,P);
		
		
		ArrayList<Point>  answer=solve(points);
		for(int i=0;i<answer.size();i++)
			System.out.println(answer.get(i).getX()+"  ,  "+answer.get(i).getY());
		
		
		
		
		
		

	}

}

猜你喜欢

转载自blog.csdn.net/weixin_41677899/article/details/84566317