我试图找到一个最佳(以复杂的方式)算法来获得我可以参加的最多课程数量。我不关心课程的总长度和课程本身。这一切都是为了尽可能多地参加课程。
给定两个数组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(其他组合也可以)
提前致谢
答案 0 :(得分:2)
这个想法是使用递归来检查所有课程。 Timothy Ha的回答解释了基本解决方案。为了清楚起见,我记得:
但您可以通过存储中间值来优化它。要做到这一点,我们将从头开始,而不是从头开始递归!
让 b 是一个初始化为0的 n 整数数组。让 b n = 1.最后,让 i = n-1
当 i > 0,执行以下操作:
当循环结束时,解决方案是 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()
返回了一个负值。
在动态编程版本中,我们只是逐步计算中间结果,我们只进行一次。因此,这是O(n)。空间复杂度也是O(n),因为我们需要存储n个中间值。
但请记住,我们必须按开始时间排序课程!使用适当的排序算法(例如,合并排序)的该操作是O(n.log(n))。因此,最终时间复杂度为O(n.log(n))。
注意:再次阅读问题后,我注意到我无法选择与之前课程结束时间相同的课程...要排除这些课程,只需转动>=
中的findMinIndex()
到>
s
答案 1 :(得分:0)
既然你评论说每个课程都需要全部参与,我认为算法可以是这样的:
按S
如果您加入S 1 ,请找到S&gt;的课程列表。 Ë<子> 1 子>;如果该列表以S k 开头,则使用递归(S k ,...,S n ),总结果为(来自递归的结果)+ 1。
如果跳过S 1 ,请使用递归(S 2 ,S 3 ,...,S n )及其来源。
选择来自步骤2和3的最大值。
UPD(来自评论)我们应该检查的不仅仅是第一步,或者递归应该存储[K-N]集的结果,以便不再计算。我可以想象一个这样的情况:S1, S2, E1, E2, S3, E3, .... SN, EN
如果我们不检查,可以在递归中计算两次[3-N](有或没有S1)