1

我有设置 S1 = {s11,s12,s13), S2 = {s21,s22,s23) 等等,直到 SN。我需要生成包含 S1,S2..SN.. 元素的所有排列,这样有每个集合中只有 1 个元素。

例如:

S1 = {a,b,c}
S2 = {d,e,f}
S3 = {g,h,i}

我的排列是:

{a,d,g}, {a,d,h}, {a,d,i}, {a,e,g}, {a,e,h}....

我该怎么做呢?(我可以随机地从每个中取出 1 个并将它们合并,但在我看来,这甚至是一个坏主意)。

为了一般性,假设每个集合中有“n”个元素。我正在考虑在 C 中实现它。请注意,'N' 和 'n' 不是固定的。

4

7 回答 7

0

如果您确切地知道有多少个集合并且它是一个很小的数字,那么通常可以使用嵌套循环来执行此操作。如果集合的数量大于 2 或 3,或者它是可变的,那么递归算法开始有意义。

如果这是家庭作业,那么实现递归算法很可能是整个作业的目标。想想看,对于每一组,你都可以递归调用枚举函数,让它开始枚举下一组……

于 2009-10-11T08:11:17.187 回答
0

如果它们在容器中,只需遍历每个:

#include <stdio.h>

int main(void)
{
    int set1[] = {1, 2, 3};
    int set2[] = {4, 5, 6};
    int set3[] = {7, 8, 9};

    for (unsigned i = 0; i < 3; ++i)
    {
        for (unsigned j = 0; j < 3; ++j)
        {
            for (unsigned k = 0; k < 3; ++k)
            {
                printf("(%d, %d, %d)", set1[i], set2[j], set3[k]);
            }
        }
    }

    return 0;
}
于 2009-10-11T08:12:49.740 回答
0

通用解决方案:

typedef struct sett
{
  int* nums;
  int size;
} t_set;


inline void swap(t_set *set, int a, int b)
{
  int tmp = set->nums[a];
  set->nums[a] = set->nums[b];
  set->nums[b] = tmp;
}

void permute_set(t_set *set, int from, void func(t_set *))
{
  int i;
  if (from == set->size - 1) {
    func(set);
    return;
  }
  for (i = from; i < set->size; i++) {
    swap(set, from, i);
    permute_set(set, from + 1, func);
    swap(set, i, from);
  }
}


t_set* create_set(int size)
{
  t_set *set = (t_set*) calloc(1, sizeof(t_set));
  int i;
  set->size = size;
  set->nums = (int*) calloc(set->size, sizeof(int));
  for(i = 0; i < set->size; i++)
    set->nums[i] = i + 1;
  return set;
}

void print_set(t_set *set) {
  int i;
  if (set) {
    for (i = 0; i < set->size; i++)
      printf("%d  ", set->nums[i]);
    printf("\n");
  }
}

int main(int argc, char **argv)
{
  t_set *set = create_set(4);
  permute_set(set, 0, print_set);

}
于 2009-10-11T08:16:24.803 回答
0

这只是一个递归问题。让我们假设这些定义。

const int MAXE = 1000, MAXN = 1000;
int N;                // number of sets.
int num[MAXN];        // number of elements of each set.
int set[MAXN][MAXE];  // elements of each set. i-th set has elements from
                      // set[i][0] until set[i][num[i]-1].
int result[MAXN];     // temporary array to hold each permutation.

功能是

void permute(int i)
{
    if (i == N)
    {
        for (int j = 0; j < N; j++)
            printf("%d%c", result[j], j==N-1 ? '\n' : ' ');
    }
    else
    {
        for (int j = 0; j < num[i]; j++)
        {
            result[i] = set[i][j];
            permute(i+1);
        }
    }
}

要生成排列,只需调用permute(0);

于 2009-10-11T08:56:28.950 回答
0

这是一个相当简单的迭代实现,您应该能够根据需要进行调整:

#define SETSIZE 3
#define NSETS 4

void permute(void)
{
    char setofsets[NSETS][SETSIZE] = {
        { 'a', 'b', 'c'},
        { 'd', 'e', 'f'},
        { 'g', 'h', 'i'},
        { 'j', 'k', 'l'}};
    char result[NSETS + 1];
    int i[NSETS]; /* loop indexes, one for each set */
    int j;

    /* intialise loop indexes */
    for (j = 0; j < NSETS; j++)
        i[j] = 0;

    do {
        /* Construct permutation as string */
        for (j = 0; j < NSETS; j++)
            result[j] = setofsets[j][i[j]];
        result[NSETS] = '\0';

        printf("%s\n", result);

        /* Increment indexes, starting from last set */
        j = NSETS;
        do {
            j--;
            i[j] = (i[j] + 1) % SETSIZE;

        } while (i[j] == 0 && j > 0);
    } while (j > 0 || i[j] != 0);
}
于 2009-10-11T09:10:58.267 回答
0

您可以将集合的元素视为循环计数器的值。3 组表示 3 个循环(如 GMan answare 中),N 组表示 N(模拟)循环:

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

int set[3][2] = { {1,2}, {3,4}, {5,6} };

void print_set( int *ndx, int num_rows ){
  for( int i=0; i<num_rows; i++ ) printf("%i ", set[i][ndx[i]] );
  puts("");
}

int main(){
  int num_cols = sizeof(set[0])/sizeof(set[0][0]);
  int num_rows = sizeof(set)/sizeof(set[0]);
  int *ndx = malloc( num_rows * sizeof(*ndx) );

  int i=0; ndx[i] = -1;
  do{
    ndx[i]++; while( ++i<num_rows ) ndx[i]=0;
    print_set( ndx, num_rows );
    while( --i>=0 && ndx[i]>=num_cols-1 );
  }while( i>=0 );
}
于 2009-10-11T11:54:38.567 回答
0

我能想出的最有效的方法(在 C# 中):

string[] sets = new string[] { "abc", "def", "gh" };
int count = 1;
foreach (string set in sets)
{
    count *= set.Length;
}

for (int i = 0; i < count; ++i)
{
    var prev = count;
    foreach (string set in sets)
    {
        prev = prev / set.Length;
        Console.Write(set[(i / prev) % set.Length]);
        Console.Write(" ");
    }

    Console.WriteLine();
}
于 2010-04-23T17:55:23.960 回答