【问题标题】:combination of combination java组合java的组合
【发布时间】:2010-09-26 22:42:44
【问题描述】:

我需要在JAVA中找到组合。

例如,我班上有 6 个学生。其中,我需要创建 4 人的组合,每组我可以选择一个亲密的 2 人组。

我必须确保没有双打(顺序无关紧要)。!并且需要打印 4 人组。

然而,这是困难的部分:

所以用数字定义学生:

如果我打印出1234作为组合之一,我不能也打印出1256,因为12同时出现在@中987654324@ 和1256

如何用 Java 编写它?

已编辑

([1,2,3,4,5],3,2) 的输出将是:

  1. 无重复组合(n=5,r=3) {1,2,3} {1,2,4} {1,2,5} {1,3,4} {1,3,5} {1,4,5} {2,3,4} { 2,3,5} {2,4,5} {3,4,5}

  2. 删除 2 个元素的重复组,只会留下我: {1,2,3} {1,4,5}(我删除了具有 12、13、23、45、14、15 组合的组,因为它们已经出现在我找到的前两个中。

【问题讨论】:

  • 致所有痴迷家庭作业的人:她有点老了:)
  • to Odelya:你能发布你期望 6 名学生(或更少学生)的输出吗?我现在不知道如何解释问题(特别是关于“亲密”群体的问题)。
  • 只是为了确保我理解:给定 N 个项目,您想生成一组子集 S,每个子集的大小为 M,这样一个子集中的两个项目不会出现在其他子集中? S的大小呢?此外,解决方案也不是唯一的。
  • @Odelya:例如对于 N=5、M=4 和 Z=2,解的大小为 1(例如 {{1,2,3,4}}),因为任何两个大小为 4 的子集至少有 2 个项目的交集。对吗?
  • @Odelya,您给出的解释不明确,因为最终结果取决于步骤 1 中生成的组合的顺序。例如如果我以相反的顺序遍历组合,最终结果将是 {3,4,5} {1,2,5}。您可能需要定义严格的迭代顺序以使结果明确。

标签: java algorithm math combinatorics combinations


【解决方案1】:

好的,这是您描述的过程的简单模拟。但是我使用二进制数来表示集合,它使操作更容易。例如,数字 19 是二进制形式的 10011:表示选择了学生 0、3 和 4(这些位置都有 1)。

先来个小帮手。

// return all subsets of 'set', having size 'subsetSize'
Set<Integer> allSubsets(int set, int subsetSize) {
    Set<Integer> result = new HashSet<Integer>();
    if (subsetSize == 0) {
        result.add(0);
        return result;
    }
    if (set == 0) {
        return result;
    }

    // check if 1st element is present
    if (set % 2 == 1) {
        // use 1st element, one less element to collect
        for (Integer i : allSubsets(set / 2, subsetSize - 1)) {
            result.add(i * 2 + 1);
        }
    }
    // not use 1st element
    for (Integer i : allSubsets(set / 2, subsetSize)) {
        result.add(i * 2);
    }

    return result;
}

还有主程序。欢迎提出建议。

    int N = 5;
    int M = 3;
    int Z = 2;

    List<Integer> result = new ArrayList<Integer>();

    // get all groups of M elements from 'wholeSet'
    int wholeSet = (1 << N) - 1;
    for (int s : allSubsets(wholeSet, M)) {
        // Check all subsets of 'Z' elements from set 's'
        boolean valid = true;
        for (int t : allSubsets(s, Z)) {
            // check if this Z-element subset already was used
            for (int past : result) {
                // check if 't' is subset of 'past' set
                if ((past|t) == past) {
                    valid = false;
                    break;
                }
            }
            if (!valid) {
                break;
            }
        }

        if (valid) {
            // none of Z-element subsets of 's' were used before
            result.add(s);
        }
    }

但它可能需要改进(如memoization)才能获得大量输入。但就目前而言,由于您没有说您期望什么样的输入,我认为这已经足够了。

【讨论】:

  • 背诵还是背诵? :)
  • @Pascal 在说了五年的“记忆”之后,很难改变你的习惯 :) 谢谢
  • @Odelya 'large numbers' 是一个模糊的定义。例如,对于输入 (50, 25, 25),结果将包含超过 2^40 个集合。超过超级计算机一个月能写的东西。
  • @Nikita - 你是如何计算 2^40 的?如果我有 (40,11,8) 需要多长时间?
  • @Odelya - 我认为这只是一个近似值。在他的示例问题中:r = 25,z = 25。与您的主要问题相关,我认为它与枚举 50 个不同数字的所有组合大小 25 的问题相同。结果数为:C(50,25)。我认为它肯定比 2^40 大很多
【解决方案2】:

假设您有一个 Student 对象,其中一个 equals 比较它们的 Primarykey。在您的示例中,学生 1 将返回 1,2 将返回 2,依此类推。

将它们全部放入集合中,这样可以确保不会出现重复。

通过 4 和 2 迭代集合,将返回您想要的结果。

【讨论】:

  • 您的答案将返回 2 组。我需要 4 组,其中没有 2 个双打。以最有效的方式。我认为你的方式并不理想
猜你喜欢
  • 2012-09-21
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 2016-06-27
  • 2023-04-02
  • 1970-01-01
  • 2023-03-21
  • 1970-01-01
相关资源
最近更新 更多