【问题标题】:Create all possible ways of putting n users into k groups创建将 n 个用户放入 k 个组的所有可能方式
【发布时间】:2013-12-05 17:49:35
【问题描述】:

给定 n 个用户 (u_1, u_2,..., u_n) 和 k 个组 (g_1, g_2, ..., g_k),创建所有组的所有可能组合。基本上,最后每个组合都是一个Map,其中第一个Integer是用户ID,第二个Integer是组ID。例如[(u_1,g_1),(u_2,g_1).. ..,(u_n, g_1)] 是一种可能的组合。

会有k^n个组合。

我搜索并看到了类似的问题,但它们确实有一些不适用于我的问题的额外条件。就我而言,每一组都没有限制,也没有均匀分布。

您能推荐一种在 Java 中执行此操作的快速方法吗?

谢谢

到目前为止我的尝试: 我尝试为每个用户的每种可能性创建一个 for 循环,但我面临的问题是我无法定义 for 循环的数量。

所以我切换到递归,但坚持为函数的内部调用创建参数。不过仍在努力。

还请注意,这不是“n 选择 k”。 “n 选择 k” 是指所有用户都相同,但这里的用户显然不相同。


好的。我为此创建了一个解决方案。基本上,这是一个动态规划问题。假设您已经为 j 个用户和 k 个位置创建了一个地图列表(组合)。要为 j+1 个用户和 k 个位置创建,需要 2 个循环:对于每个 Map,对于每个 i=1 到 k,Map.put(user_j+1, k))。 Is既是递归的又是迭代的。递归,因为您需要将旧地图传递给新的迭代。就是这样。

【问题讨论】:

  • 您的问题没有说明您为尝试解决问题所做的工作;它目前读起来像是对代码的请求。请分享您尝试的实施,并说明它如何无法满足您的要求。
  • 你应该使用 Prolog 来处理这样的事情 :P 但我猜这是一个家庭作业,你至少应该展示你到目前为止所做的尝试
  • 是的,我们可能可以提供一种快速的方法!但是你做了什么?
  • 为什么用户不一样?请出示问题说明。

标签: java algorithm combinations


【解决方案1】:

这类问题的传统解决方案是使用递归:如果有 n = 0 个用户,则唯一可能的分组是空组。否则,取出第一个用户并为其他 n-1 个用户生成解决方案。使用子问题的解决方案,通过将第一个用户分配到 k 个可能的组中的每一个来生成最终解决方案。

在代码中:

import java.util.*;

class Grouping {
    public static void main(String[] args) {
        List<?> groups = grouping(Arrays.asList(1,2,3), Arrays.asList(4,5,6,7));
        System.out.println(groups.size());
        System.out.println(groups);
    }

    static List<Map<Integer,Integer>> grouping(List<Integer> users, List<Integer> groups) {
        if (users.isEmpty()) {
            Map<Integer,Integer> empty = Collections.emptyMap();
            return Collections.singletonList(empty);
        } else {
            Integer user = users.get(0);
            List<Map<Integer,Integer>> subs = grouping(users.subList(1,users.size()), groups);

            List<Map<Integer,Integer>> solutions = new ArrayList<>();
            for (Integer group: groups) {
                for (Map<Integer,Integer> sub : subs) {
                    Map<Integer,Integer> m = new HashMap<>(sub);
                    m.put(user, group);
                    solutions.add(m);
                }
            }
            return solutions;
        }
    }
}

【讨论】:

  • 终于有人理解了这个问题并给出了正确的解决方案:)。顺便说一句,我确实在你发布之前就做到了,但是,看到这个还是很高兴的。其他人不断给出错误的解决方案,当我指出它不正确时,他们有点生气。 :)
  • 我看到你发帖后已经找到了解决方案,听起来你的解决方案和这个很相似。关于反应,我猜“组合”这个词让很多人望而却步,因为它具有精确的含义。
  • 是的,我也喜欢这个。我的建议在实现方面看起来有点矫枉过正,但应该提供相同的结果和运行时复杂性。无论如何,递归是正确的方法,谢谢 Joni。
【解决方案2】:

好的,这是一个简单的想法。
我们首先假设每个 user_id 在 {0, ... n-1} 中,group_id 在 {0, ... k-1} 中,我们可以稍后将这些数字映射回真实 id。

现在,您基本上想要做的是遍历 Base k 数字系统中的所有 n 位数字,即每个数字 0 因此,您以数字 0000...00(n 个零)开头,以 kkkk....kk(名义 k 的 n 位数字)结束。对于每个这样的数字,位置表示 user_id,数字值是该用户的 group_id。

所以,您需要实现的主要工作是类 Combination 代表这样的 n 位序列(尝试 ArrayList 或简单的 int[] array),正确实现 increment() 操作(我想递归是最好的进行此实现的方法)。可能您还可以使用方法isMaxReached() 来检查所有数字是否具有k 的值。

然后你会有一个循环:

组合组合 = new Combination(); // 用 n -zeroes 初始化

while (!combination.isMaxReached()) {
    combination.increment();
}

如果您需要有关实施的更多详细信息,请告诉我。

希望对您有所帮助。

【讨论】:

    【解决方案3】:

    看起来我们有以下内容:

    1. n不同的号码(用户)
    2. k 集(组)

    目标是:

    • 找到所有具有 k 个集合 S_k 的 k 元组,使得对于 1..k 中的所有 i,j,S_i 和 S_j 的成对交集为空,并且并集 S_1 .. S_k 是集合1..n

    如果这是你想要的,那么我会递归地攻击它:

    • 如果 n 为 0,则结​​果是 1 k 元组的空集。
    • 如果 n 为 1,则结果为 k 个元组,其中对于 j = 1..k 的所有元素 S_j,除了设置为 {1} 的第 j 个元素之外,它是空集。
    • 如果 n 是 m,则计算 m-1 的元组列表。然后复制列表 k 次,让第 i 个集合为第 i 个集合和 {n} 的并集。 (请注意,这只是前面 n=1 规则的更一般形式)。

    例子:

    n = 3, k = 2
        n = 2, k = 2
            n = 1, k = 2
                n = 0, k= 2
                result: [({},{})]
            result: [({1},{}), ({},{1})]
        result: [({1,2},{}), ({2},{1}),         // j=1, union 1st with {2}
                 ({1},{2}), ({},{1,2})]         // j=2, union 2nd with {2}
    result: [
        ({1,2,3},{}), ({2,3},{1}), ({1,3},{2}), ({3},{1,2}), // j=1, union 1st with {3}
        ({1,2},{3}), ({2},{1,3}), ({1},{2,3}), ({},{1,2,3})  // j=2, union 2nd with {3}
    ]
    

    【讨论】:

      【解决方案4】:

      所以你想要像 k1,n1, k1,nN .. kN,nN..这样的地图

      1. 您将需要 2 个循环
      2. 从循环组开始。在每个组中,遍历所有用户...在第二个循环中,将(组,用户)放入哈希图中...
      3. 使用上述算法的代码。

      【讨论】:

      • 但这不会生成 n^k 组合...它会生成 n * k
      • 如果你有 2 个组和 3 个用户..告诉我你怎么能创建超过 2*3 = 6 个排列?你将如何得到 2^3 = 8 ?
      • 这只创建了 n*k 个组,这是我到目前为止所得到的。
      • @TheLostMind:每个用户有k个选项,所以组合的总数是k^n
      • @Simo 你到底想要什么?根据您的问题,您想输入&lt;user, group&gt;Map&lt;Integer, Integer&gt;。这仅在 n * k 中完成
      猜你喜欢
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-02
      • 1970-01-01
      • 2020-07-16
      • 1970-01-01
      相关资源
      最近更新 更多