创建将n个用户放入k个组的所有可能方法

时间:2013-12-05 08:43:19

标签: java algorithm combinations

给定n个用户(u_1,u_2,...,u_n)和k个组(g_1,g_2,...,g_k),创建所有组的所有可能组合。基本上,最后,每个组合都是Map< Integer,Integer>,其中第一个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))。是递归和迭代。递归,因为您需要将旧映射传递给新迭代。就是这样。

4 个答案:

答案 0 :(得分:4)

这类问题的传统解决方案是使用递归:如果有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;
        }
    }
}

答案 1 :(得分:2)

好的,这是一个简单的想法 让我们首先假设每个user_id在{0,... n-1},并且group_id在{0,... k-1},我们可以稍后将这些数字映射回实际ID。 / p>

现在,您基本上想要做的是通过 Base k 数字系统中的所有n位数字进行迭代,即每个数字0 <= base&lt; ķ。
所以,你从数字开始是0000 ... 00(n-neroes),你以kkkk .... kk(n个名义 k )结束。对于每个这样的数字,位置表示user_id,数字值是该用户的group_id。

因此,您需要实现的主要工具是表示此n位数序列的类Combination(尝试ArrayList或简单int[] array),并执行increment()操作正确(我认为递归是执行此实现的最佳方式)。可能您也可以使用方法isMaxReached()来检查所有数字是否都有值k

然后你会有一个循环:

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

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

如果您需要更多有关实施的详细信息,请与我们联系。

希望有所帮助。

答案 2 :(得分:0)

看起来我们有以下内容:

  1. n不同的数字(用户)
  2. k设置(群组)
  3. 目标是:

    • 找到所有具有k个集合S_k的k元组,这样对于所有i,j在1..k中,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}
    ]
    

答案 3 :(得分:-1)

所以你想要像k1,n1,k1,nN ... kN,nN等地图。

  
      
  1. 您需要2个循环
  2.   
  3. 首先循环播放群组。在每个组中,循环遍历所有用户......并在第二个循环中,将(组,用户)放入散列映射...
  4.   
  5. 使用上述算法的代码。
  6.