合并天际线,分而治之

时间:2013-02-20 10:17:53

标签: c# algorithm data-structures divide-and-conquer

我正试图解决着名的天际线问题(见gif):

输入

  

(1,11,5),(2,6,7),(3,13,9),(12,7,16),(14,3,25),(19,18,22) ,(23,13,29),(24,4,28)

应该返回,其他建筑物后面的点应该消失,Y轴的变化坐标应该在返回的天际线中:

  

(1,11),(3,13),(9,0),(12,7),(16,3),(19,18),(22,3),(23,13) ,(29,0)

我试图通过对算法使用分而治之的方法来实现,以实现O(n lg n)的运行时间,但是我被困在合并部分。

每当我想到它,我都会感到困惑。例如,我检查天际线是哪一个,例如它具有较低的x坐标,然后我将它的高度添加到我的新天际线。但后来我遇到了另外两个天际线后面的天际线,我怎么才能发现这个“碰撞”?

首先通过检查left.x2<来检查天际是否有任何重叠。 right.x1?但是我想我应该先检查一下?在x轴上重叠优先级,一切都变成了一个鸡蛋大的混乱。

也许我觉得太复杂了?我需要的是每个交叉点的最高y坐标集,我应该像这样接近吗?

2 个答案:

答案 0 :(得分:7)

我认为这应该是一种更容易解决问题的方法:

  • 将x坐标拆分为每个矩形的开始和结束对象,如下所示:

    rect(x1, y, x2) -> (x1, y, "start", reference to rect),
                       (x2, y, "finish", reference to rect)
    

    类似于:

    class MyStruct
    {
       Rectangle rect;
       int x, y;
       bool isStart;
    }
    
  • 按x坐标(O(n log n)
  • 对这些对象进行排序
  • 创建一个(最初为空)矩形集(将按y坐标排序,例如BST
  • 循环浏览这些对象(按现在排序的顺序)(O(n)
    • 每当遇到开始时
      • 将矩形添加到矩形集(O(log n)
      • 如果是新的最高矩形,请将该起点添加到输出(O(1)
    • 每当遇到结束时
      • 从矩形集(O(log n)
      • 中删除矩形
      • 如果它是最高的矩形,请找到集合中的下一个最高矩形,并将点(current.finishX, new.y)添加到输出(O(1))(如果集合为空,则添加(current.finishX, 0)到而不是输出)

所以O(n log n)

答案 1 :(得分:0)

这可以通过修改合并排序算法来实现。天际线的算法如下:

<强> ConstructSkyLine

    ConstructSkyLine(List B ) --------------- O(nlogn)
    {
        If(B.size() == 1)
        {
            List skyLineList = new List();
            SKYLINE = new SKYLINE(B.XL, B.XR, B.H);
            skyLineList.add(SKYLINE);
            Return skyLineList;
        }
        B1, B2 <-- Split(B);
        List S1 <-- ConstructSkyLine(B1);
        List S2 <-- ConstructSkyLine(B2);
        List S <-- MergeSkyline(S1, S2);
        Return S;
    }

<强> MergeSkyline

    MergeSkyline(List S1, List S2) --------------- O(n)
    {
        List< SKYLINEENTRY> skylineEntryList = new ArrayList<SKYLINEENTRY>();
        while (S1.isEmpty() && S2.isEmpty())--------------- O(n)
        {
           S1Item <-- S1.get(0);
           S2Item <-- S2.get(0);
           If (S1Item.XL < S2Item.XL)
           {
             Merge(S1, S2, skylineEntryList);   --------------- O(n)
           }
           Else
           {
             Merge(S2, S1, skylineEntryList); --------------- O(n)
           }
         }

         If(!S1.isEmpty())
         {
            skylineEntryList.add(S1);
         }

         If(!S2.isEmpty())
         {
           skylineEntryList.add(S2);
         }
         Retrun skylineEntryList;
      }

合并

  Merge(S1, S2, skylineEntryList) --------------- O(n)
  {
    SKYLINEENTRY <-- null;
    S1Item <-- S1.get(0);
    S2Item <-- S2.get(0);
    SKYLINEENTRY.XL = S1Item.XL;
    If(S1Item.XR > S2Item.XL) // means over lap 
    {
        If(S1Item.H > S2Item.H) // S1 is higher.
        {
           SKYLINEENTRY.XR = S1Item.XR;
           SKYLINEENTRY.H = S1Item.H;
           S1.remove(S1Item); --------------- O(n)
           skylineEntryList.add(SKYLINEENTRY);
           if(S2Item.XR < S1Item.XR) // full overlap
           {
              S2.remove(S2Item); --------------- O(n)
           }
           Else // partial overlap
           {
              S2Item.XL <-- S1Item.XR;
           }            
        }
        Else //S2 is higher
        {
           SKYLINEENTRY.XR = S2Item.XL;
           SKYLINEENTRY.H = S1Item.H;
           if(S2Item.XR < S1Item.XR) // full overlap with S2
           {
              S1Item.XL = S2Item.XR;
           }
           Else // partial overlap
           {
              S1.remove(S1Item); --------------- O(n)
           }    
           skylineEntryList.add(SKYLINEENTRY);  
        }   
     }
     Else // no overlap
     {
        SKYLINEENTRY.XR = S1Item.XR;
        SKYLINEENTRY.H = S1Item.H;
        S1.remove(S1Item); --------------- O(n)
        skylineEntryList.add(SKYLINEENTRY);
     }
  }