【问题标题】:Creating all possible subset of k and m combinations of n items in C [duplicate]在C中创建n个项目的k和m个组合的所有可能子集[重复]
【发布时间】: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, 3}{0} 
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, 2}{3, 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 固定。对我来说,这听起来很像一个分组问题(组合问题的一个子类型)。有趣..
  • @nullqube 感谢您的建议,但递归代码并没有完全按照要求执行,并且最后的非递归代码在分段错误中崩溃

标签: c algorithm combinations


【解决方案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 语言的算法或代码吗?
猜你喜欢
  • 2012-10-11
  • 1970-01-01
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
相关资源
最近更新 更多