查找所有可能的组合而不重复选择?

时间:2013-03-15 06:25:12

标签: c algorithm combinations

你怎么写一些东西从阵列{1,2,3,...,N-1,N}中选择所有可能的三元组合而不重复?这是来自最近举办的编程竞赛。 N是3的倍数。

使用数组{1,2,3,4,5,6}的示例:

C_1 = { {1,2,3}, {4,5,6} }
C_2 = { {1,2,4}, {3,5,6} }
C_3 = { {1,2,5}, {3,4,6} }

都有效,但

C_bad1 = { {1,2,3}, {3, 4, 5} }
C_bad2 = { {1,2,4}, {3, 5, 6}, {1, 2, 5} }

不是。

4 个答案:

答案 0 :(得分:2)

由于N是3的倍数,我们可以使用技巧来解决它:

  1. 按升序生成所有排列数字
  2. 对于每个排列, 将数字直接划分为3组(0-2,3-6,...,N-2..N)
  3. 这应该可以在没有太多花哨工作的情况下为您提供结果。

    编辑:我正在等待有人发现上述问题并确实发现了。修复重复的方法是采取额外步骤:

    步骤3:如果任何三元组按字典顺序排序,则丢弃该组。其他继续。

答案 1 :(得分:2)

你有(N!)/(((3!)^(N / 3))*((N / 3)!))位置(prove)。你可以使用递归算法来提供来自数组{1,2,3,...,N-1,N}的三元组的所有可能组合,而不需要重复。 但是为了产生其中一个,你可以使用任何想法,例如user1952500想法(虽然这个算法也生成(N / 3)!位置重复)或每个,例如你不变的最后 - (N-6) - 成员并在结果开始时将你的解决方案作为前6名成员。(此算法不会产生重复的位置)

递归解决方案:

void combtriples(int begin)
    {
     for(int i=1;i<=(n/3);i++)
      for(int j=1;j<=(n/3);j++)
       for(int k=1;k<=(n/3);k++)
        {
         if ((mark[i]<3) && (mark[j]<3) && (mark[k]<3))
          {
           count-position++;
           c[count][3]=begin;
           c[count][4]=begin+1;
           c[count][5]=begin+2;
           mark[i]++;
           mark[j]++;
           mark[k]++;
           count-member-flase=count-member-flase+3;
           if (count-member-flase > 0)
           {
             combtriples(begin+3);
           }
          }
         }
    }


    int main()
    {
     int mark[];
     int c[][];
     count-position=0;
     count-member-flase=0;
     combtriples(1);
    return 0;
    }

答案 2 :(得分:1)

#include <stdio.h>

#define SEL_NUM 3
#define LIST_SIZE 6

void printset(int *list, int *map, int size);
void select(int *list, int *map, int n, int size, int start);

int main(int argc, const char **argv) {
  int list[LIST_SIZE] = {1, 2, 3, 4, 5, 6};
  int map[LIST_SIZE] = {0};

  select(list, map, SEL_NUM, LIST_SIZE, 0);

  return 0;
}

void select(int *list, int *map, int n, int size, int start) {
  if (n == 0) {
    printset(list, map, size);
    return;
  }
  for (int i = start; i < size; i++) {
    map[i] = 1;
    select(list, map, n - 1, size, i + 1);
    map[i] = 0;
  }
}

void printset(int *list, int *map, int size) {
  int list1[SEL_NUM], list2[SEL_NUM], list1cnt = 0, list2cnt = 0;
  for (int i = 0; i < size; i++)
    if (map[i])
      list1[list1cnt++] = list[i];
    else
      list2[list2cnt++] = list[i];
  for (int i = 0; i < list1cnt; i++)
    printf(" %d ", list1[i]);
  printf(" -- ");
  for (int i = 0; i < list2cnt; i++)
    printf(" %d ", list2[i]);
  printf("\n");
}

答案 3 :(得分:0)

让我们考虑N有多少这样的不同三元组。首先将T = floor(N / 3)定义为N个元素支持的每组中三元组的数量。然后请注意,由于不需要重复三元组​​,因此每个三元组中的三元组可以按第一元素递增排序而不失一般性。那么N的三元组总数是:

产品为t:0 - &gt; ((N - 3 * t - 1)*(N - 3 * t - 2)/ 2)的T-1

从这个公式可以直接看到如何构建(强力)算法来生成三元组。

更新:以上仅适用于N%3 == 0.我正在进行概括。强制;见OP的评论

案例:

  1. N <3产生0
  2. N = 3产生1
  3. N = 6,产率(5×4/2)×(2×1/2)= 10
  4. N = 9产量(8 * 7/2)*(5 * 4/2)*(2 * 1/2)= 28 * 10 = 280
  5. 当你参加编程比赛时,我认为你不需要任何代码。

    更新#2: 请注意,要自动消除重复项,必须将每个三元组的第一个元素强制为编号最小的未选择元素。