【问题标题】:Recursive function counting and printing partitions of 1 to n-1递归函数计数和打印 1 到 n-1 的分区
【发布时间】:2015-05-07 15:02:21
【问题描述】:

我正在尝试编写一个递归函数(它必须是递归的)来打印出 1 到 n-1 的分区和分区数。 例如,4 个组合的总和为 4:

1 1 1 1
1 1 2
1 3
2 2

我只是在这个功能上遇到了很多麻烦。下面这个功能不起作用。有人可以帮帮我吗?

 int partition(int n, int max)
{

  if(n==1||max==1)
    return(1);
  int counter = 0;
  if(n<=max)
    counter=1;
  for(int i = 0; n>i; i++){
          n=n-1;
          cout << n << "+"<< i <<"\n";
          counter++;
          partition(n,i);         
        }

  return(counter);
}

【问题讨论】:

  • “下面的这个函数不起作用” - 它有什么作用? 提供样本输入会输出什么?您是否了解为什么它会这样做或有任何怀疑为什么它似乎不起作用?
  • 最大值为 n-1。输出它: 请输入数字:4 3+0 2+0 1+0 1+1 2+1 计数器:2 @WhozCraig
  • 因此,给定一个数字 N,您希望找到所有 唯一 个自然数集,每个自然数集在 [1, N) 范围内,以递归方式总和为 N ?
  • 是,但在 1 到 n-1 的范围内
  • @CSCI_newbie 我想出了一个解决方案。这一切都不是那么容易。这里有一些提示:让你的递归函数获取 N、当前总和、当前的被加数数组和被加数的数量。递归的基本情况是当 sum == N 时。在这种情况下,只需打印数组并返回。看看你是否能找出递归的情况。首先递归地打印出总和的所有排列,然后找出如何将其减少到只有唯一的和数集,可能会更容易。

标签: c++ recursion partition


【解决方案1】:

这是解决问题的良好开端:

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

void partition(int n, int sum, int *summands, int num_summands)
{
  int i;

  if (sum == n)  // base case of recursion
  {
    if (num_summands > 1)  // don't print n by itself
    {
      for (i = 0; i < num_summands; ++i)
        printf("%d ", summands[i]);

      printf("\n");
    }
  }
  else
  {
    /* TODO: fill in recursive case */
    /* Iteratively recurse after appending one additional, varying summand to summands */
    /* It might be easier to first generate all permutations of the sums */
    /* and then figure out how to reduce that down to only the unique sets of summands (think sorting) */
  }
}

int main(int argc, char **argv)
{
  if (argc == 1)
  {
    printf("usage: %s <num>; where num > 1\n", argv[0]);
    return 1;
  }

  int n = atoi(argv[1]);

  if (n <= 1)
  {
    printf("usage: %s <num>; where num > 1\n", argv[0]);
    return 1;
  }

  int summands[n+1];               // NOTE: +1's are to make summands[-1] always safe inside recursion

  summands[0] = 1;                 // NOTE: make summands[-1] == 1 at top level of recursion
  partition(n, 0, summands+1, 0);  // NOTE: +1's are to make summands[-1] always safe inside recursion

  return 0;
}

如果您需要对找到的总和进行计数,则可以向partition 添加一个额外参数,该参数是一个指向 (int) 到目前为止找到的总和计数的指针。您只会在打印基本情况下增加该计数。在 main 中,您将传递一个指向零初始化整数的指针,而在递归中,您只需传递指针。当您返回 main 时,您可以打印找到的总和数。

【讨论】:

    【解决方案2】:

    这是一个简单的伪代码,看你懂不懂,初始调用是用recPartition(n,1)

    int A[100]
    int n
    int cnt = 0
    recPartition(int remaining,int indx)
        if(remaining <0 )
           return
        if(remaining == 0)
            print from 1 to indx in A
            ++cnt
            return
        for i from 1 to remaining
             if(i!=n)
                 A[indx] = i
                 recPartition(remaining-i,indx+1) 
    

    【讨论】:

    • 如果我们用 4 来调用它,它不会打印“1 1 1 1\n2 \n2 1 \n3 \n2 1 1 \n2 \n3 1 \n”吗???
    • 是的,我们可以轻松地将值保存在外部数组中。编辑了答案
    • 这样更好,但它不仍然会进行所有排列吗?例如在 4 上,“1 1 2”和“2 1 1”?
    • OP 没有要求所有排列,他需要他的示例中的所有组合
    • 我知道。我是说你的算法多次产生相同的组合(作为彼此的排列)。
    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-18
    • 2015-02-09
    • 2022-01-13
    • 2022-11-17
    • 1970-01-01
    相关资源
    最近更新 更多