【问题标题】:Algorithm design to partition a set of students into groups将一组学生分组的算法设计
【发布时间】:2020-11-14 02:14:05
【问题描述】:

我正在学习算法设计,我看到了这个问题:问题:我们有 n 个学生(从 1 到 n 编号)。学生需要分组进行课堂活动。每个学生都有自己小组中有多少学生的偏好。具体来说,学生 i 希望他们组中的学生人数在 x[i] 和 y[i] (含)之间。换句话说,如果组(那个学生 i 被分配到)有 G 个人,那么 x[i] ≤ G ≤ y[i] 必须成立。每个学生都必须被分配到一个小组(即使小组只有一名学生)。 给定 n 和 x[], y[],算法应该确定这是否可能。

以下是一些示例:

示例 1:n = 5, (x[], y[]) = { (1, 2), (1, 3), (2, 3), (2, 2), (3, 3) }。

我们可以将学生 1 和学生 4 分配到一个组(该组的人数为 2),将其他三个学生分配到另一个组。这样就可以满足大家的约束了。

示例 2:n = 5, (x[], y[]) = { (1, 2), (1, 2), (2, 3), (2, 2), (3, 3) }。

不可能满足学生 5 的约束,因为只有两个学生对 3 大小的小组“还行”(而学生 5 只希望小组中正好有 3 个学生)。

示例 3:n = 5, (x[], y[]) = { (1, 1), (2, 2), (2, 2), (2, 5), (2, 4) }。

学生 1 可以分配到一个独奏组。学生 2-5 可以被任意分配到两个大小为 2 的小组(因为每个人都可以在他们的小组中有 2 个学生)。因此,存在许多解决方案。

我的第一个想法是按照 y[i] 对数组进行排序,然后从第一个元素开始,根据 y[i] 的值将人分组。但是在示例 2 的情况下会发生什么?

我的第二个想法是按x[i]+y[i]对数组进行排序,由于y[i]大于x[i],我们可以从第一个元素开始,将人分组(但i认为第一个想法更好)

总的来说,我觉得这2个算法都不够用,我在找更足够的(如果有的话)

【问题讨论】:

标签: java algorithm sorting dynamic-programming computer-science


【解决方案1】:

我认为您的第一个解决方案非常出色,示例 2 没有任何问题。

  1. 当然,您首先按 y[i] 对数组进行排序。然后从最大到最小。
  2. 如果无法创建此大小的组 - 请确保可以移动到较小的大小(例如,没有一个组具有只有一个可能大小的“严格”条件)。例如,在情况 2 中,因为学生 5 没有此选项,所以这是不可能的,因此算法将立即返回 False。

【讨论】:

    【解决方案2】:

    我找到了一个多项式解决方案,主要基于根据偏好的限制条件进行排序。

    注意几点:

    1. 如果某人有像[x, x] 这样的偏好 => 这是最严格的,因为我们应该为他找到一组大小正好x
    2. 另一方面,宽松的偏好大小for ex. [1, 1000] => 限制最少,在考虑更多限制性偏好之前不必考虑
    3. 在形成组时,一旦达到最大尺寸 => 假设组已形成 ;例如[1,1] => group of size 1 is ready

    代码准备 :: class=组

    在实现时,我认为如果我创建一个Group class 来维护它会容易得多:

    1. 组的所有成员(成员根据他们的喜好)
    2. 组的合并最小规模
    3. 合并组的最大大小
    4. validity-checker-method 来确定组是否最终有效。例如[(3, 3), (2, 3)] 不是有效组

    如何从初始首选项列表开始

    如上所述,我们需要根据最严格到最不严格的偏好对偏好列表进行排序,即y[i]-x[i]

    时间复杂度:O(N^2)

    这是 Python 中的工作代码:

    from typing import List
    
    class Group:
        def __init__(self, s: int, e: int):
            self.members = [(s, e)]
            self.min, self.max = s, e
    
        def add_member(self, s: int, e: int):
            self.members.append((s, e))
            self.min, self.max = max(self.min, s), min(self.max, e)
    
        def can_fit(self, s: int, e: int) -> bool:
            return not (self.reached_maxsize() or (e < self.min or s > self.max))
    
        def reached_maxsize(self) -> bool:
            return len(self.members) == self.max
    
        def check_group_validity(self) -> bool:
            num_members = len(self.members)
            return self.min <= num_members <= self.max
    
    
    def create_groups(preference_list):
        groups: List[Group] = []
        preference_list = sorted(preference_list, key=lambda x: (x[1] - x[0], x[0], x[1]))
    
        for pref in preference_list:
            found_group = False
            for grp in groups:
                if grp.can_fit(pref[0], pref[1]):
                    grp.add_member(pref[0], pref[1])
                    found_group = True
                    break
            if not found_group:
                groups.append(Group(pref[0], pref[1]))
    
        # check groups-validity
        if all(group.check_group_validity() for group in groups):
            return groups
    
        print("No grouping is possible")
        return []
    
    
    res = create_groups([(1, 2), (1, 3), (2, 3), (2, 2), (3, 3)])
    print([x.members for x in res])
    
    res = create_groups([(1, 2), (1, 2), (2, 3), (2, 2), (3, 3)])
    print([x.members for x in res])
    
    res = create_groups([(1, 1), (2, 2), (2, 2), (2, 5), (2, 4)])
    print([x.members for x in res])
    

    测试输出:

    [[(2, 2), (1, 2)], [(3, 3), (2, 3), (1, 3)]]
    
    No grouping is possible
    []
    
    [[(1, 1)], [(2, 2), (2, 2)], [(2, 4), (2, 5)]]
    

    【讨论】:

      猜你喜欢
      • 2017-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-16
      • 2021-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多