【问题标题】:The "Waiting lists problem"“等候名单问题”
【发布时间】:2009-01-09 21:35:49
【问题描述】:

许多学生想要进入某个班级的各个部分,有些学生已经注册了一个部分但想要更改部分,所以他们都进入了候补名单。只有当有人从该部分掉线时,学生才能进入新的部分。没有学生愿意放弃他们已经进入的部分,除非可以确保进入他们正在等待的部分。每个部分的等候名单先到先得。

让尽可能多的学生进入他们想要的部分。

上述问题很快就会演变成僵局。我的问题是;这个问题有已知的解决方案吗?


一个简单的解决方案是依次选择每个部分,并强制等待列表中的第一个学生进入该部分,然后检查是否有人在事情解决后最终辍学(O(n) 或更多部分)。这在某些情况下可行,但我认为可能有更好的选择,包括强制一个以上的学生进入一个部分(O(n) 或更多学生数量)和/或一次操作多个部分(O (坏):-)

【问题讨论】:

  • 标记为“家庭作业”。这可能不是你的作业,但可能是某人的作业,因为几年前我在大学时遇到过这个问题。
  • 改为非我的作业以更好地反映现实
  • 哈哈“不是我的作业”。因此,如果我要找到“我的作业”的答案,这实际上是说它不是 我的 作业? :/ 天啊.. 我迷路了..
  • 标签是用来描述问题的,而不是它的所有者。

标签: algorithm language-agnostic theory


【解决方案1】:

嗯,这只是归结为在类的有向图中找到循环对吗?每个链接都是一个想要从一个节点到另一个节点的学生,任何时候你找到一个循环,你就删除它,因为这些学生可以相互解决他们的需求。当你没有周期时,你就完成了。

【讨论】:

  • 不完全是因为如果学生放弃旧班级和等待名单的队列方面,则要求学生进入新班级。列表中 /second/ 人的边缘应该指向哪里?
  • 哦,是的,我读得太快了。哦,再想一想,我可能不明白。为什么你不能直接放弃循环,除非你说“放弃循环需要第一个投掷器处于无等级的边缘,直到循环解决,这不是一个选择”?
  • 问题是循环非常大,每个学生都必须在循环中出现两次。如果 x、y 和 z 想要交换,只有当 x、y 和 z 在等待列表中排在首位时才能这样做。如果 a 在列表 2 中的 y 之前,则必须移动 a 或找到包含 x、y、z 和 a 的循环。
  • 不是将每条边设为学生,而是将其设为学生的排序链表,如果“删除”循环,只需弹出每条边的第一个学生,只有在没有更多时才将其删除学生在排队。
【解决方案2】:

好的,让我们试试。我们有 8 名学生 (1..8) 和 4 个部分。每个学生都在一个部分,每个部分有 2 名学生的空间。大多数学生都想转学,但不是全部。

在下表中,我们可以看到学生的当前部分、他们需要的部分以及队列中的位置(如果有)。

+------+-----+-----+-----+
| stud | now | req | que |
+------+-----+-----+-----+
|    1 |   A |   D |   2 |
|    2 |   A |   D |   1 |
|    3 |   B |   B |   - |
|    4 |   B |   A |   2 |
|    5 |   C |   A |   1 |
|    6 |   C |   C |   - |
|    7 |   D |   C |   1 |
|    8 |   D |   B |   1 |
+------+-----+-----+-----+

我们可以在图表中呈现这些信息:

+-----+           +-----+           +-----+
|  C  |---[5]--->1|  A  |2<---[4]---|  B  |
+-----+           +-----+           +-----+
   1               |   |               1
   ^               |   |               ^
   |              [1] [2]              |
   |               |   |               |
  [7]              |   |              [8]
   |               V   V               |
   |               2   1               |
   |              +-----+              |
   \--------------|  D  |--------------/
                  +-----+

我们试图找到一个有空缺的部分,但没有找到。所以因为所有部分都满了,我们需要一个肮脏的把戏。所以让我们随机选择一个非空队列。在这种情况下,A 部分假设它有一个额外的位置。这意味着学生 5 可以进入 A 部分,在 C 部分留下一个空缺,由学生 7 占据。这在 D 部分留下一个空缺,由学生 2 占据。我们现在在 A 部分有一个空缺。但我们假设该部分A有一个额外的位置,所以我们可以去掉这个假设,得到一个更简单的图。

如果路径从未返回到 A 部分,请撤消移动并将 A 标记为无效起点。用另一个部分重试。 如果没有剩余的有效部分,我们就完成了。

现在我们有以下情况:

+-----+           +-----+           +-----+
|  C  |           |  A  |1<---[4]---|  B  |
+-----+           +-----+           +-----+
                   |                   1
                   |                   ^
                  [1]                  |
                   |                   |
                   |                  [8]
                   V                   |
                   1                   |
                  +-----+              |
                  |  D  |--------------/
                  +-----+

我们用另一个随机部分重复这个技巧,这解决了图形。

如果您从几个当前未分配的学生开始,您可以添加一个额外的虚拟部分作为他们的起点。当然,这意味着任何部分都必须有空缺,否则问题无法解决。

请注意,由于队列中的顺序,可能没有解决方案。

【讨论】:

  • 好答案。但我仍然不确定它会一直有效。为了表明最能证明的是,如果根本存在任何解决方案,那么您可以通过将一个学生添加到某个部分来减少问题。您可能会找到一个案例,您需要强制 2 名或更多学生来减少蚂蚁。
  • 我可以想象,有些情况只能通过重新洗牌来解决。目标是最大化集体幸福感,而不是个人幸福感,因此如果没有其他解决方案,可以忽略排队顺序。
  • 如果队列被解释为加权边,那么问题可以转化为找到每个边循环的最小权重并旋转它。 OTOH,您可以构建一个案例,该案例找到了一个解决方案,可以移动理想人数但会插队,我无法说服自己在某些情况下它也不会不理想。
【解决方案3】:

这实际上是一个图问题。您可以将这些等待列表依赖项中的每一个视为有向图上的边。如果这个图有一个循环,那么你有你描述的情况之一。一旦你确定了一个循环,你可以通过“过度填充”其中一个类来选择任何点来“打破”循环,并且你会知道事情会正确解决,因为图中有一个循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多