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());
}
}