分治法求二維凸包問題java
阿新 • • 發佈:2018-12-09
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());
}
}