找到我可以参加的最多课程数量

时间:2014-11-06 12:26:54

标签: algorithm

我试图找到一个最佳(以复杂的方式)算法来获得我可以参加的最多课程数量。我不关心课程的总长度和课程本身。这一切都是为了尽可能多地参加课程。

给定两个数组S和E. S [i]包含课程的开始时间,E [i]包含相应的结束时间。数组已按E排序。由于我不是Flash,我无法加入第一个结束时间等于下一个开始时间的课程。

以下是一个例子:

S = [
    "2014-11-06 01:00:00",
    "2014-11-06 03:00:00",
    "2014-11-06 07:00:00",
    "2014-11-06 09:00:00",
    "2014-11-06 09:00:00"
]

E = [
    "2014-11-06 05:00:00",
    "2014-11-06 06:00:00",
    "2014-11-06 08:00:00",
    "2014-11-06 09:00:00",
    "2014-11-06 10:00:00"
]

对于这些值,正确的答案是3,因为我可以参加课程1,3和5(其他组合也可以)

提前致谢

2 个答案:

答案 0 :(得分:2)

核心理念

这个想法是使用递归来检查所有课程。 Timothy Ha的回答解释了基本解决方案。为了清楚起见,我记得:

  1. 按S
  2. 排序课程
  3. 从S 1开始
  4. 查找 k = min( j,E 1 < S j )。如果存在,找到最适合 S k ,...,S n
  5. 如果 k > 2(=当前课程+ 1),找到最适合 S 2 ,...,S n
  6. 返回步骤3和步骤4之间的最佳匹配。
  7. 使用动态编程进行时间优化

    但您可以通过存储中间值来优化它。要做到这一点,我们将从头开始,而不是从头开始递归!

    b 是一个初始化为0的 n 整数数组。让 b n = 1.最后,让 i = n-1

    i > 0,执行以下操作:

    1. 考虑我们选择 i 课程。我们必须找到 k = min( j,E i < S j )。如果存在这样的 k ,则会强制执行 i +1≤k
    2. 如果 k 存在,那么 b i = max(1 + b k ,b <子> i + 1的 的)。
    3. 否则, b i = b i + 1 (我们不必明确说明“max(1, b i + 1 )“,因为1≤ b i + 1
    4. 减少 i 并继续执行步骤1.
    5. 当循环结束时,解决方案是 b 1

      这是C方式的解决方案

      // I suppose S[] is sorted by increasing order
      // E[] are the end times associated with S :
      // (the course that starts at S[i] ends at E[i]
      int findBestNumber(ADateType S[], ADateType E[], int n) {
          int i = n-1, k, res;
          int *sol = NULL;
          if(!(sol = malloc(n*sizeof (int))))
              return -1;
          memset(sol, 0, sizeof (*sol));
          sol[n-1] = 1;
          while(i-- > 0) {
              k = findMinIndex(E[i], S);
              if(k >= 0) // k exists
                  sol[i] = max(1 + sol[k], sol[i+1]);
              else // k does not exist, we return a value like -1
                  sol[i] = sol[i+1];
          }
          res = sol[0];
          free(sol);
          return res;
      }
      

      findMinIndex(after, S)搜索最小索引 k ,以便在≤ S k 之后。由于S在调用此函数时已排序,因此它是一个简单的二进制搜索。在上面,如果我们找不到这样的索引,我认为我们从findMinIndex()返回了一个负值。

      DP 版本的空间和时间复杂度

      动态编程版本中,我们只是逐步计算中间结果,我们只进行一次。因此,这是O(n)。空间复杂度也是O(n),因为我们需要存储n个中间值。

      但请记住,我们必须按开始时间排序课程!使用适当的排序算法(例如,合并排序)的该操作是O(n.log(n))。因此,最终时间复杂度为O(n.log(n))。

      Bonus:一个有效的C实现

      On Ideone

      注意:再次阅读问题后,我注意到我无法选择与之前课程结束时间相同的课程...要排除这些课程,只需转动>=中的findMinIndex()> s

答案 1 :(得分:0)

既然你评论说每个课程都需要全部参与,我认为算法可以是这样的:

  1. 按S

  2. 排序课程
  3. 如果您加入S 1 ,请找到S&gt;的课程列表。 Ë<子> 1 ;如果该列表以S k 开头,则使用递归(S k ,...,S n ),总结果为(来自递归的结果)+ 1。

  4. 如果跳过S 1 ,请使用递归(S 2 ,S 3 ,...,S n )及其来源。

  5. 选择来自步骤2和3的最大值。

  6. UPD(来自评论)我们应该检查的不仅仅是第一步,或者递归应该存储[K-N]集的结果,以便不再计算。我可以想象一个这样的情况:S1, S2, E1, E2, S3, E3, .... SN, EN如果我们不检查,可以在递归中计算两次[3-N](有或没有S1)