【问题标题】:Complex permutation/combination复杂排列/组合
【发布时间】:2012-06-27 15:28:02
【问题描述】:

摘要:
您选择您注册的模块。
每个模块都有多个组。
每个组代表给定模块的讲座。
每个组合应仅包含每个模块中的一个组。

示例:
COS 121 -3 组
COS 132 -2 组

这将为您提供 6 个选项:[1,1],[1,2],[2,1],[2,2],[3,1],[3,2]

我的角度: 我需要使用每个组合来生成时​​间表,所以我使用一个数组来存储当前正在使用的组和组的总数:arrSubjects[subject,currentGroup,maxGroups]

从逻辑上讲,您应该能够遍历此数组以利用每个组组合。

我只是无法掌握这个解决方案,可能是因为我使用了错误的角度。任何帮助/建议将不胜感激。

我目前的实现: 我对此感到很尴尬,因为这需要很多时间,但它确实有效。 下面是基本的伪代码:

for (all the groups multiplied with eachother) do {
  for (all the modules selected) do {
    Select a random group between 1 and the nmr of groups 
  }
}

之后我必须删除所有重复项。

提前致谢

我目前正在处理的代码:

arrPermutations[0,0]:=1;//Current group for 1st module
arrPermutations[0,1]:=3;//Max groups for 1st module
arrPermutations[1,0]:=1;
arrPermutations[1,1]:=3;
arrPermutations[2,0]:=1;//Current group for 3rd module
arrPermutations[2,1]:=3;//Max groups for 3rd module
iCurrent:=iMax; //2
while (arrPermutations[0,0]<=arrPermutations[0,1]) do
begin
//Display arrPermutations
if arrPermutations[iCurrent,0]=arrPermutations[iCurrent,1] then
begin
  Inc(arrPermutations[iCurrent-1,0]);
  for i := iCurrent to iMax do
    arrPermutations[i,0]:=1;
  iCurrent:=iMax;
end else
begin
  Inc(arrPermutations[iCurrent,0]);
end;
end;

目前我只遍历最后两组。 这是我检查时得到的输出:
============运行1==============
模块,当前组,最大组
1,1,3
2,1,3
3,1,3
============运行2===============
模块,当前组,最大组
1,1,3
2,1,3
3,2,3
============运行3==============
模块,当前组,最大组
1,1,3
2,1,3
3,3,3
============运行 4===============
模块,当前组,最大组
1,1,3
2,2,3
3,1,3
============运行5===============
模块,当前组,最大组
1,1,3
2,2,3
3,2,3
============运行6==============
模块,当前组,最大组
1,1,3
2,2,3
3,3,3
============运行7==============
模块,当前组,最大组
1,1,3
2,3,3
3,1,3
============运行8==============
模块,当前组,最大组
1,1,3
2,3,3
3,2,3
============运行9==============
模块,当前组,最大组
1,1,3
2,3,3
3,3,3
============运行10===============//////这里有问题
模块,当前组,最大组
1,1,3
2,4,3
3,1,3

【问题讨论】:

    标签: data-structures permutation combinations


    【解决方案1】:

    新答案:

    首先,可能的组合数是每个模块中组数的乘积。例如,如果有 3 个模块,分别包含 5、2 和 7 组,则有 5*2*7 = 70 种可能的组合。称之为 TOTALCOMBOS。

    因此,如果您想遍历所有可能的组合,您只需从 0 循环到 TOTALCOMBOS-1。

    for I in 0..TOTALCOMBOS-1 do
        COMBO = (convert I to a combination)
        (do something with COMBO)
    

    现在,要将索引转换为组合,将整数索引视为从右到左的“数字”列表会有所帮助。这最容易看出每个模块是否有十个组,以及组号是否从 0 而不是 1 开始。然后可以将整数 468 读取为列表 (8,6,4),这意味着来自模块 1 的组 8,模块 2 中的第 6 组,模块 3 中的第 4 组。在伪代码中,将索引转换为组合类似于

    DIGITS = I
    for M in 1..(number of modules) do
       D = DIGITS mod (number of groups in module M)
       DIGITS = DIGITS / (number of groups in module M)
       (add group D from module M to the current combination)
    

    如果您希望组号从 1 而不是 0 开始,则只需在最后一行使用组 D+1,而不是组 D。

    旧答案:

    使用递归。递归函数可以获取一个模块列表,并返回一个组合列表。每个组合将包含来自输​​入列表中每个模块的一组。

    作为基本情况,如果模块列表为空,则返回一个空的组合列表。

    否则,让 M 成为第一个模块,让 REST 成为其余模块。调用 REST 上的递归函数以获取其余模块的所有组合(调用此组合列表 COMBOS)。请注意,COMBOS 中的这些组合包含来自 M 的组。

    现在,我们将列出所有组合,这次包括来自 M 的组。将列表 ANSWERS 初始化为空。使用两个嵌套循环。对于 M 中的每个组 G,以及 COMBOS 中的每个组合 C,将 G 添加到 C,并将此扩展组合添加到 ANSWERS。

    返回答案。

    (假设:没有一个组出现在一个以上的模块中,或者在同一个模块中出现两次。没有一个模块出现在模块列表中超过一次。如果你愿意,你可以放宽这些假设,但你需要定义什么你希望这种行为出现在这些情况下。)

    (注释 1:我在上面说“列表”,但所有这些列表都可以很容易地成为数组或其他类型的容器。)

    (注释2:我说“将G添加到C”的地方,重要的是C本身不要改变,因为它会被重复使用很多次,M中的每个组一次。)

    【讨论】:

    • 嗨,克里斯。感谢您快速而彻底的回复。尽管我正在专门寻找一种顺序通过排列的方法,因为我想利用每个排列而不必存储它。请查看我更新的帖子以获得更好的理解。
    • 好的,听起来你想要某种数组。如果您只是希望能够在不存储所有组合的情况下迭代组合,我已经修改了答案。
    • 嗨,克里斯。该算法完美运行!我真的很感谢你的帮助。你让我有信心更频繁地使用 stackoverflow!
    猜你喜欢
    • 2012-06-16
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-11
    • 2019-03-14
    • 1970-01-01
    相关资源
    最近更新 更多