【问题标题】:Divide and Conquer Hull Algorithm分而治之的赫尔算法
【发布时间】:2011-11-15 18:42:32
【问题描述】:

您好,我今天的问题是分解并弄清楚如何对算法的 LOWER TANGENT 部分进行实际编码,我已设法完成步骤 (1) 和 (2),但我现在卡在步骤 (3) 上。

分而治之的凸壳

船体(S):

(1) 如果 |S|

(2) 否则,将点集 S 划分为两个集合 A 和 B,其中 A 由 x 坐标最低的点的一半和 B 组成 由 x 坐标最高的点的一半组成。

(3) 递归计算 HA = Hull(A) 和 HB = Hull(B)。

(4) 通过计算 HA 和 HB 的上下切线并丢弃所有点 位于这两条切线之间。

http://www.cs.wustl.edu/~pless/506/l3_1.gif

寻找下切线

下切线(HA ; HB):

(1) 设 a 为 HA 的最右边点。

(2) 设 b 为 HB 的最左边点。

(3) 虽然 ab 不是 HA 和 HB 的下切线

(a) 虽然 ab 不是 HA 的下切线,但 a = a - 1(顺时针移动 a)。

(b) 虽然 ab 不是 HB 的下切线,但 b = b + 1(逆时针移动 b)。

(4) 返回 ab.

引用自:http://www.cs.wustl.edu/~pless/506/l3.html 这个解释最能描述我的问题。

没有包含 Lexisort 和 convehull 的函数,因为它们正在工作,DC hull 算法已包含在内以提供上下文。

我当前的代码:

public static int [][] dcHull(int [][]merged){

    if(merged.length <= 3)
        return convexHull(merged);

    else {

        lexiSort(merged);
        //split(P, A, B);
        //SPLIT
        double p = merged.length;
        int A;
        int B;

        if (p%2 == 0){//EVEN
            A = (int) (p/2);
            B = (int) (p/2);
        }
        else//ODD
            A = (int) (1+(p/2));
            B = (int) (p/2);



        int arrayA[][] = new int[A][2]; 
        int arrayB[][] = new int[B][2];

        for (int i=0; i<A; i++){
            arrayA[i][0] = merged[i][0];
            arrayA[i][1] = merged[i][1];
        }

        for (int i=0; i<B; i++){
            arrayB[i][0] = merged[i+A][0];
            arrayB[i][1] = merged[i+A][1];
        }

        for ( int i=0; i<arrayA.length; i++){
            System.out.println( "Merged array A Coordinates: " + arrayA[i][0] +", " + arrayA[i][1]);}
        for ( int i=0; i<arrayB.length; i++){
            System.out.println( "Merged array B Coordinates: " + arrayB[i][0] +", " + arrayB[i][1]);}

        lowerT(arrayA, arrayB);
        //upperT(arrayA, arrayB);


        return merged(dcHull(convexHull(arrayA)), dcHull(convexHull(arrayB)));

    }

}

public static int[][] lowerT(int [][] hulla, int [][]  hullb){

    int a = 0;
    int b = 0;

    //LOWER TANGENT
    //(1) Let a be the rightmost point of HA .
    for (int i=0; i<hulla.length; i++){
        if (a < hulla[i][0]){
            a = hulla[i][0];
        }
    }
    //(2) Let b be the leftmost point of HB .
    for (int i=0; i<hullb.length; i++){
        if (b < hullb[i][0]){
            b = hullb[i][0];
        }
    }
    for (int i=0; i<hullb.length; i++){
        if (b > hullb[i][0]){
            b = hullb[i][0];
        }
    }

代码在计算出 HA 的 a 和 HB 的 b 后完成,但是我不明白 (3) 或更确切地说如何使用我拥有的元素对其进行编码。

(1) 设 a 为 HA 的最右边点。

(2) 设 b 为 HB 的最左边点。

我认为还有一种称为右转的附加代码方法很有用: “下切线是一个条件,可以 通过两个顶点的方向测试进行局部测试,并且 船体上的相邻顶点。”

我只是不知道如何组合起来。

public static boolean rightTurn(int [][] rt, int counter) //AxBxC = (Bx-Ax)(Cy-Ay)-(By-Ay)(Cx-Ax)
{
    int ax = rt[counter-2][0];
    int bx = rt[counter-1][0];
    int cx = rt[counter][0];

    int ay = rt[counter-2][1];
    int by = rt[counter-1][1];
    int cy = rt[counter-0][1];
    int result =(bx-ax)*(cy-ay)-(by-ay)*(cx-ax);

    if (result < 0){                            // Result = VE+ (Right Turn), 0, VE- (Left Turn)

        return true;                                                    //VE- = TRUE = Right Turn
    }

    else return false;                                                  //VE+ = FALSE = Left Turn
}

【问题讨论】:

  • 这是很多人必须阅读和理解的工作。你有没有机会把它配对一下,以便更容易提供一些帮助?
  • 对不起,我没有早点回复你,我还没习惯这个系统。当然,我将来会更明确地格式化我的问题。 =)

标签: java


【解决方案1】:

首先,

//(2) Let b be the leftmost point of HB .
for (int i=0; i<hullb.length; i++){
    if (b < hullb[i][0]){
        b = hullb[i][0];
    }
}
for (int i=0; i<hullb.length; i++){
    if (b > hullb[i][0]){
        b = hullb[i][0];
    }
}

似乎有一个剩余的复制粘贴。

现在,让我们尝试更改“但是我不明白 (3) 或更确切地说如何使用我拥有的元素对其进行编码”。

(a) 虽然 ab 不是 HA 的下切线,但 a = a - 1(顺时针移动 a)。

因此,您需要测试一条直线是否是 HA 的下切线。这里的几何情况简化了测试。基本面当然是 HA 的凸性。所考虑的直线,L,总是通过 HA 的一个顶点,比如 v,和 HB 的一个顶点,比如 b。让两个相邻的顶点是 uw,标记为使得 u, v, w 是顺时针方向的一块边界。有三种可能, 1. uw 都在L之上或之上,那么,通过凸性,L > 是 HA 的下切线; 2. uw之一位于L之上或之上,另一个位于之下; 3. 都在L之下。

w 位于 L 下方当且仅当路径 bvwv 处左转。u 位于 L 下方当且仅当路径 bvuv 处左转。 p>

您需要一个函数来检查路径 ABC 是否在 B 处左转(角度小于 180°)。您的 rightTurn 有要点,但参数错误,因为您要测试的点之一属于另一个船体。并测试你的标志是否正确,很容易滑到那里。

因此,当 v 的两个邻居中的任何一个位于通过 bv 的直线下方时,替换 v em> 按其顺时针邻居并再次检查。挑选邻居时注意数组边界。

经过几个步骤,您会找到一条直线,它是 HA 的下切线,但通常不是 HB。

(b) 虽然 ab 不是 HB 的下切线,但 b = b + 1(逆时针移动 b)。

这是类似的,但方向发生了变化。 HB 边界上的一点 p 位于通过 a(HA 的一个顶点)和 b(HB 的考虑顶点)的直线下方) 当且仅当路径 pbab 处左转。

在 HB 的边界上逆时针选择邻居直到找到 HB 的下切线 围绕 HA 边界上的顶点 a 旋转线,使得 HB 的下切线不必是 a HA 的下切线不再(看你链接的图片)。

所以回到 3 (a)。这将使线绕 b 旋转,可能旋转到不再是 HB 的下切线。 3 (b) 再次。
迭代直到找到两者的下切线。

aIndex = findRightmostA();
bIndex = findLeftmostB();
while(!(lowerTangentA (aIndex, bIndex) && lowerTangentB(aIndex, bIndex))){
    aIndex = findLowerTangentA(aIndex, bIndex);
    bIndex = findLowerTangentB(aIndex, bIndex);
}

lowerTangentA(aIndex, bIndex){
    ux = hulla[aIndex+1][0];
    uy = hulla[aIndex+1][1]; // array bounds!
    ax = hulla[aIndex][0];
    ay = hulla[aIndex][1];
    wx = hulla[aIndex-1][0];
    wy = hulla[aIndex-1][1];
    bx = hullb[bIndex][0];
    by = hullb[bIndex][1];
    return !(leftTurn(bx,by,ax,ay,ux,uy) || leftTurn(bx,by,ax,ay,wx,wy));
}

找到两个船体的上切线是类似的。尝试抽象切线检查是值得的,这样您就可以对所有检查(下/上,HA/HB)使用相同的功能。

【讨论】:

    猜你喜欢
    • 2013-02-02
    • 1970-01-01
    • 2012-01-01
    • 2013-02-03
    • 2017-06-08
    • 2013-01-12
    • 2019-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多