1. 程式人生 > >分治法求二維凸包問題java

分治法求二維凸包問題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()); } }