【问题标题】:Merge skylines, divide and conquer合并天际线,分而治之
【发布时间】:2013-02-05 07:20:37
【问题描述】:

我正在尝试解决著名的天际线问题(见 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

也许我想得太复杂了?我需要的是一组最高的 y 坐标,在每个路口,我应该这样接近它吗?

【问题讨论】:

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


    【解决方案1】:

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

    • 将 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)

    【讨论】:

    • 让我看看如果我理解正确,通过拆分您的意思的 x 坐标,例如,(2, 4, 8) -> (2, 4), (8, 0), 对?
    • 抱歉,我不清楚您所说的“当前矩形”是什么意思。只是初始矩形的列表?
    • 对不起,也许我太笨了,但我还是不明白。每当遇到 start 时:将其添加到矩形集合中,但我们刚刚确定这些结构不是矩形
    • @Oxymoron 您将对象的矩形成员添加到集合中。
    • 如何“找到集合中的下一个最高矩形”O(1)?
    【解决方案2】:

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

    构建天际线

        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(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);
         }
      }
    

    【讨论】:

      猜你喜欢
      • 2012-09-08
      • 2018-09-11
      • 1970-01-01
      • 2013-11-09
      • 2016-04-04
      • 1970-01-01
      • 2013-01-31
      • 2011-12-31
      • 2012-03-04
      相关资源
      最近更新 更多