【问题标题】:Detecting Conflicts on a Scheduler Timeline (Algorithm)检测调度程序时间线上的冲突(算法)
【发布时间】:2018-03-28 10:54:07
【问题描述】:

假设我在类似于 Outlook 的 24 小时日历上使用 (StartTime,EndTime) 绘制事件。我的目标是检测重叠(冲突)并将它们拆分,使每列占据窗口宽度的 N%,其中 N = 该时间范围内的冲突总数。

我的问题是,我的算法

1) first, sort all events by StartTime
2) LOOP: looks at neighbors: CurrentEvent and NextEvent (n+1):

   if NextEvent exists {

      if (CurrentEvent EndTime > NextEvent StartTime) { // CONFLICT!
         overlappingMode = true;
         overlappingEvents.add(currentEvent); // Add to array
      }
      else {  // NO CONFLICT
         if (overlappingMode is TRUE) {
            // Resolve Now
            redrawOverlappingEvents(overlappingEvents);
            // Reset
            overlappingMode = false;
            EMPTY overlappingEvents;
         }
      }
   }

3) After the loop, also for the last element, 

   if (Overlap Mode is still TRUE) {
      overlappingEvents.add(currentEvent); // Add to array also
      // Now Resolve
      redrawOverlappingEvents(overlappingStartTimes);
      // Reset
      overlappingMode = false;
      EMPTY overlappingEvents;    
   }

这在大多数情况下都有效,但会给 EndTimes 带来某种问题。例如,考虑下图:

最后一个事件应该是 Split-Group of 4(不是 3 个)的一部分。它没有被包含在冲突拆分中,因为之前的事件的EndTime 与它的StartTime 不冲突。

在 StartTimes 的 Sorted 数组中,倒数第二个事件的 EndTime (4:30) 与最后一个事件的 StartTime (4:45) 不冲突。所以最后一个事件4:45 - 6:00 没有被包含在整个拆分组中。我应该为跨越 02:30 - 06:00 的时间区域获得一个 4 列拆分布局。

我的算法是正确的还是有更好的方法?

【问题讨论】:

    标签: algorithm sorting recursion


    【解决方案1】:

    问题在于“冲突”关系不是可传递的,因此不是等价关系,但您需要等价关系,这样您就可以将它们放入共享水平宽度的等价类中。为此,我们必须定义一个新的关系,它是一个等价关系(因此是可传递的),然后弄清楚如何计算它。

    获得等价关系就像对“冲突”关系进行传递闭包一样简单。也就是说,我们可以“添加”所有缺失的成员以使关系具有传递性。做到这一点的一种方法是保持您的代码大致相同,但不要记住最后的开始/结束时间,而是记住第一个(因此最早;我们仍然需要排序)开始时间和最近的停止时间,并使用它检测“冲突”:

       // first event is the current event
       lastMaxEndTime = CurrentEvent EndTime
    
       if NextEvent exists {
    
          // if the maximum end time considered in
          // the conflicting component currently
          // under consideration extends beyond the
          // the next event's start time, then this
          // and everything that "conflicts" with it
          // is also defined to "conflict" with NextEvent
          if (lastMaxEndTime > NextEvent StartTime) { // CONFLICT!
             overlappingMode = true;
             overlappingEvents.add(currentEvent); // Add to array
             lastMaxEndTime = max(lastMaxEndTime, NextEvent EndTime)
          }
          else {  // NO CONFLICT
             if (overlappingMode is TRUE) {
                // Resolve Now
                redrawOverlappingEvents(overlappingEvents);
                // Reset
                overlappingMode = false;
                EMPTY overlappingEvents;
             }
    
             // everything that starts earlier than me,
             // ends before I start. so start over
             lastMaxEndTime = NextEvent EndTime
          }
       }
    

    在您的示例中,算法执行以下操作:

    lastMaxEndTime = 2:00
    lastMaxEndTime > 2:30? no, so
        lastMaxEndTime = 3:30
    lastMaxEndTime > 3:00? yes, so
        lastMaxEndTime = max(3:30, 5:00) = 5:00
    lastMaxEndTime > 3:15? yes, so
        lastMaxEndTime = max(5:00, 4:30) = 5:00 <--- this fixed it
    lastMaxEndTime > 4:45? yes, so
        lastMaxEndTime = max(5:00, 6:00) = 6:00
    

    【讨论】:

    • 是的,这行得通。非常感谢!我仍然需要考虑如何更新 Max 以证明这个算法是正确的——我会考虑正式的证明。
    • @geneb。如果你有正式的证明,请张贴!如果您需要帮助,请告诉我,我会看看我能做些什么。
    • 嗨帕特里克,我有一个关于这个算法的后续问题,发布在这里:stackoverflow.com/questions/47039201/… 有什么想法吗?谢谢
    • @geneb。我对另一个问题发表了评论并提供了答案。 Prune 的另一个(较早的)答案是正确且易于理解的。我尝试证明 Prune 的答案并提出另一种方法(没有证据证明它是最佳的)。
    • 非常感谢帕特里克。现在正在审查,将在几天内接受/确认。非常感谢您的帮助!
    猜你喜欢
    • 2015-12-19
    • 2016-05-02
    • 2018-04-12
    • 2017-03-21
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    • 2017-07-17
    相关资源
    最近更新 更多