繁体   English   中英

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

[英]Create all possible ways of putting n users into k groups

给定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))。 是递归和迭代。 递归,因为您需要将旧映射传递给新迭代。 而已。

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

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

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

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

然后你会有一个循环:

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

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

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

希望有所帮助。

看起来我们有以下内容:

  1. n不同的数字(用户)
  2. k集(组)

目标是:

  • 找到所有具有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}
]

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM