幾何問題中的分治法

幾何問題中的分治法

1.最近對問題

問題描述:

設p1=(x1,y1),p2=(x2,y2),…,pn=(xn,yn)一共n個點構成點集S,最近點對問題就是找出集合中距離最近的兩個點,嚴格來說最近點對可能多於一個,但我們簡單起見只找出一對即可。

算法思路:

(1)劃分:將集合S分成兩個子集S1和S2,根據平衡子問題原則,每個子集中大約有n/2個點,設集合S的最近點對是pi與pj(1<=i,j<=n),則會出現三種情況。
①pi在S1中,pj在S1中
②pi在S2中,pj在S2中
③pi在S1中,pj在S2中
(2)劃分①②可以遞歸,劃分③比較麻煩
(3)合併,比較三種情況取最小值返回即可
下面討論情況③:
在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述

代碼:

import org.junit.Test;
public class AVL {
    //最近點對問題
   @Test
    public  void Test()
    {
        Point p1 = new Point();
        p1.setX(0.1);
        p1.setY(0.2);

        Point p2 = new Point();
        p2.setX(0.4);
        p2.setY(0.3);

        Point p3 = new Point();
        p3.setX(0.2);
        p3.setY(0.1);

        Point points[]=new Point[]{p1,p2,p3};
        Point[] points_help = new Point[points.length];
        for(int i=0;i<points.length;i++){
            points_help[i]=new Point();
        }
        //排序橫軸
        sort(points,0,2,0);
        //驗證sort函數
        for (Point point : points) {
            System.out.println(point);
        }
        System.out.println(MiniDisttance(points,0,2,points_help));
    }

    //編寫函數將點集按照排序,condition爲0表示按照橫座標排序,爲1表示按照縱座標排序
    int Partition(Point points[],int left,int right,int condtion){
       int i=left,j=right;
        Point temp=new Point();
        temp = points[i];
       if(condtion==0)
       while(i<j){
           while(i<j&&points[j].x>=temp.x)
               j--;
           points[i]=points[j];
           while(i<j&&points[i].x<=temp.x)
               i++;
           points[j]=points[i];
       }
       else{
           while(i<j){
               while(i<j&&points[j].y>=temp.y)
                   j--;
               points[i]=points[j];
               while(i<j&&points[i].y<=temp.y)
                   i++;
               points[j]=points[i];
           }
       }
       points[i]=temp;
       return i;
    }

    void  sort(Point points[],int left,int right,int condtion){
       if(left<right){
           int partition = Partition(points, left, right, condtion);
           sort(points,left,partition-1,condtion);
           sort(points,partition+1,right,condtion);
       }
    }
    //在使用MiniDistance函數之前我們假設points已經按照x排好序了
    double MiniDisttance(Point points[],int left,int right,Point points_help[]){
       //如果只有兩個點返回即可
        if(right-left==1){
            getDistance(points[left],points[right]);
        }//如果有三個點
        else if(right-left==2){
            double d1 = getDistance(points[left],points[left+1]);
            double d2 = getDistance(points[left+1],points[left+2]);
            if(d1<d2){
                return d1;
            }else
                return d2;
        }
        int mid = (left+right)/2;
        //最近點對在左半邊
        double d1 = MiniDisttance(points,left,mid,points_help);
        //最近點對在右半邊
        double d2 = MiniDisttance(points,mid+1,right,points_help);
        //比較d1與d2的大小
        double d;
        if(d1<d2)
            d= d1;
        else
            d= d2;
        //接下來尋找在mid左右兩邊都爲d範圍內的點並並將其保存
        double mid_left = points[mid].x-d;
        double mid_right = points[mid].y+d;
        int index =0;
        //收集P1與P2的點
        for(int i=mid-1;i>=left;i--){
            if(points[mid].x-points[i].x<=d)
                points_help[index++]=points[i];
            else
                break;

        }
        for(int j=mid+1;j<=right;j++){
            if(points[j].x-points[mid].x<=d){
                points_help[index++]=points[j];
            }
            else
                break;
        }
        //現在已經收集好了我們將其按照y軸的方向從小到大排序
        sort(points_help,0,index-1,1);
        for(int i=0;i<index;i++){
            for(int j=i+1;j<index;j++){
                if(getDistance(points_help[i],points_help[j])<d)
                    d=getDistance(points_help[i],points_help[j]);
                else
                    break;
            }
        }
        return d;
    }

    double getDistance(Point p1,Point p2){
       return Math.sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
    }
}

class Point{
    public void setX(double x) {
        this.x = x;
    }

    @Override
    public String toString() {
        return "Point{" +
                "x=" + x +
                ", y=" + y +
                '}';
    }

    public void setY(double y) {
        this.y = y;
    }

    double x;
    double y;

}

輸出:
在這裏插入圖片描述

2.凸包問題

問題描述:設p1=(x1,y1),p2=(x2,y2),…,pn=(xn,yn)是平面上n個點構成的集合S,凸包問題是爲集合S構造最小凸多邊形。
在這裏插入圖片描述
在這裏插入圖片描述
由於最近比較忙碌,就先介紹到這吧,後續有空會補上代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章