在C中创建n个项目的k和m个组合的所有可能子集[重复]

Posted

技术标签:

【中文标题】在C中创建n个项目的k和m个组合的所有可能子集[重复]【英文标题】:Creating all possible subset of k and m combinations of n items in C [duplicate] 【发布时间】:2018-09-02 07:18:08 【问题描述】:

我正在寻找解决问题的方法: 我必须编写一个代码来计算唯一元素的组合,即选择作为组的 n 个元素的所有不同组合 k 元素并重新计算剩余子集的新组合,无需复制。 给定 S,所有可能的唯一元素的集合,我必须计算 S 的元素的唯一组合的子集 T,现在我有 重新计算一个新的子集 - V - T 和所有子集 T 和 V 的组合必须是唯一的:

For example I have this set S: 0, 1, 2, 3, 4

我必须得到

a 0, 1 2, 3  4 
b 0, 1 2, 4  3 
c 0, 1 3, 4  2 
d 0, 2 1, 3  4 
e 0, 2 1, 4  3 
f 0, 2 3, 4  1 
g 0, 3 1, 2  4 
h 0, 3 1, 4  2 
i 0, 3 2, 4  1 
j 0, 4 1, 2  3 
k 0, 4 1, 3  2 
l 0, 4 2, 3  1 
discarded as the same as g -> 1, 2 0, 3  4 
discarded as the same as j -> 1, 2 0, 4  3 
m 1, 2 3, 4 0 
discarded as the same as d -> 1, 3 0, 2  4 
discarded as the same as k -> 1, 3 0, 4  2 
n 1, 3 2, 4 0 
discarded as the same as e -> 1, 4 0, 2  3 
discarded as the same as h -> 1, 4 0, 3  2 
o 1, 4 2, 30 
discarded as the same as a -> 2, 3 0, 1  4 
discarded as the same as l -> 2, 3 0, 4  1 
discarded as the same as o -> 2, 3 1, 4  0 
discarded as the same as b -> 2, 4 0, 1  3 
discarded as the same as i -> 2, 4 0, 3  1 
discarded as the same as n -> 2, 4 1, 3  0 
discarded as the same as c -> 3, 4 0, 1  2 
discarded as the same as f -> 3, 4 0, 2  1 
discarded as the same as m -> 3, 4 1, 2  0 

组合 1, 2 0, 3 4 与 0, 3 1, 2 4 的(对于这个问题)相同,然后必须丢弃,与 1, 2 相同0, 4 3 和 0, 4 1, 2 3。

是否有可能在不使用考虑了已经获得的组合的数据结构(作为列表)的情况下达到目标?

我需要这样的东西:Generating Combinations: 1

这不是上一个问题的重复,因为研究涉及必须被认为是单义的分区,即其中包含的元素(无论它们的顺序如何)在以前的细分中必须不是已经同意的,例如 1 , 2 0, 4 3 和 0, 4 1, 2 3 必须被认为是非唯一的,因此只有组合有效:0, 4 1, 2 3

【问题讨论】:

我可能弄错了,但在您的示例中,您为 5 个元素的独特组合提供了 24 个可能的结果。通常不是 120 个结果吗? 2, 1 0, 3 4 在哪里?此外,T 子集的值是否强制配对?不能是 0, 1, 23, 4 吗?你能给出一个 S 中 3 和 4 元素的完整例子吗? @Tom 的 2, 1 0, 3 4 不存在,因为不同的订单(在一个集合内)被认为是相同的组合,所以 2, 1 0 , 3 4 与 0, 3 1, 2 4 相同。 T 不是强制配对的,在本例中是配对的。 因此,每个“组合”是一组无序的n/k 无序的k 元素集,以及一个无序的n%k 元素集,每个完整“组合”中的所有唯一元素,取自一组 n 独特元素,k 固定。对我来说,这听起来很像一个分组问题(组合问题的一个子类型)。有趣.. rosettacode.org/wiki/Combinations#C @nullqube 感谢您的建议,但递归代码并没有完全按照要求执行,并且最后的非递归代码在分段错误中崩溃 【参考方案1】:

这比我最初想象的要复杂。

好的,假设你有“n”个 uniq 元素。 uniq 可能性的总数是“n!” (所以对于 5 个元素,你有 120 种可能性)。

假设您想将“k”个数字组成“组”。

因此,如果 n = 5 且 k = 2,您将得到您的示例:

0, 1, 2, 3, 4。

现在,乐趣就从这里开始: 为了知道当前命题是否不是重复的,您可以丢弃每个 complete 组中的第一个数字未排序的每个命题。

例如:

0, 1, 2, 3, 4。

在这里,1 和 3 是无用的,因为它不是完整组的第一个值,而 4 是不完整组的一部分。 所以有趣的是

0, ?, 2, ?, ?。

0, 2 是否已排序?是的,所以你可以保留这个提议。 这意味着如果你有

2, 3, 0, 1, 4。

不好,因为

2, ?, 0, ?, ?。

2, 0 未排序。


如果你有 n = 6 和 k = 2,那么是

0, 2, 3, 4, 1, 5

有效吗?不,因为 0 3 1 未排序。 你可以看到

0, 2, 1, 5 , 3, 4

是有效的排序命题。


现在,如果我们知道 n 和 k,是否有可能计算出有多少个有效命题?

是的。

也许吧。 我想 ... 如果我能找到什么,我会更新。

编辑:

Aaaaannnd,这里是一个实现。做点有趣的事... 它基于前面的算法,所以当然如果我的算法是假的,那么这段代码就是假的。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>



#define N 5
#define K 2


void Comb_Display(int proposition[N])

    printf("");
    for (int i = 0; i < N; ++i) 
        if (i && i % K == 0) 
            printf(" ");
        
        printf("%d%s", proposition[i], (i && (i + 1) % K == 0) || i + 1 >= N ? "" : ", ");
    
    printf("\n");


bool Comb_Valid(int proposition[N])

    int nbGroup = N / K;

    if (nbGroup == 1) 
        return (true);
    
    for (int i = 0; i < nbGroup; i += K) 
        if (proposition[i] > proposition[i + K]) 
            return (false);
        
    
    return (true);


void Comb_MakeMagicPlease(int numberAvailable[N], int proposition[N], int ind)

    // We are at the end of the array, so we have a proposition
  if (ind >= N) 
    printf("%s : ", Comb_Valid(proposition) ? "OK" : "  "); // O = Valide, ' ' = invalide
    Comb_Display(proposition);
    return;
  

  // We scan "numberAvailable" in order to find the first number available
  for (int i = 0; i < N; i++) 
    if (numberAvailable[i] != -1) 
        int number = numberAvailable[i];

        numberAvailable[i] = -1; // We mark the number as not available

      proposition[ind] =  number;
      Comb_MakeMagicPlease(numberAvailable, proposition, ind + 1);
      numberAvailable[i] = number; // we mark the number as available
    
  


int main(void)

  int numberAvailable[N];
  int proposition[N];

  for (int i = 0; i < N; ++i) 
    numberAvailable[i] = i + 1;
  

  Comb_MakeMagicPlease(numberAvailable, proposition, 0);
  return 0;

【讨论】:

如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review 感谢您的信息,我会记住的,但这更像是一个悬而未决的问题,而不是一个真正的问题。 @Tom 感谢您的代码,但它有一个错误,它返回 OK : 1, 5 2, 3 4 and 2, 3 5, 1 4 作为“OK”值,但实际上它们是相同的值,所以只有没有一个可以是“OK” 那么你只需要修改“Comb_Valid”函数来检查每个子集 ., ., . 是否在内部排序。为什么要排序?因为如果我们有一个子网的元素“a,b,c”,那么你可以有 6 个子网:abc,acb,bac,bca,cab,cba。我们怎么能只保留一个?好吧,我们可以看到,当其他 5 个没有排序时,只有一个是“排序的”(abc)。这与子网组的原理相同。那么,既然您知道每个子网可以保留或不保留,这取决于是否已排序,为什么不尝试一下呢? @Tom's,你能更新你的代码吗?【参考方案2】:

是的。

在这种情况下,请确保结果已排序。这样你只输出一个排序的版本,而不必检查是否已经获得了组合。

您也可以使用它来加快生成速度。 IE。选择 1,2 后,尝试以 0 开头的任何内容都没有意义,因此您可以跳过这些内容。

【讨论】:

你能帮我用 C 语言的算法或代码吗?

以上是关于在C中创建n个项目的k和m个组合的所有可能子集[重复]的主要内容,如果未能解决你的问题,请参考以下文章

已知n个正数:wi, 1<=i<=n, 和M。要求找出{wi }的所有子集使得子集内元素之和等于M。例如: n=4, (w1,w2,w3,w4)=(11,13,24,7),

在java中创建一个算法来查找所有可能的集群

从多个集合中创建所有可能的组合

R从n个元素的字符向量中生成大小为m的所有可能组合[重复]

组合数例题

洛谷 P2822 组合数问题