1

M给定一个大小为和的矩阵N,我们希望用整数值 (>=0) 填充每一行,使其总和为某个值。

请注意,M和的维度N是使用特定公式预先计算的,因此可以保证在给定所需条件的情况下匹配填充(即下面的 sum_val)。

这是在 R 中的Partition library下实现的。

library(partitions)

# In this example, we impose condition 
# that each rows must sum up to 2 in total
# And each row has 5 columns
sum_val <- 2
n <- 5
#The above two parameters are predefined.

t(as.matrix(compositions(sum_val, n)))
      [,1] [,2] [,3] [,4] [,5]
 [1,]    2    0    0    0    0
 [2,]    1    1    0    0    0
 [3,]    0    2    0    0    0
 [4,]    1    0    1    0    0
 [5,]    0    1    1    0    0
 [6,]    0    0    2    0    0
 [7,]    1    0    0    1    0
 [8,]    0    1    0    1    0
 [9,]    0    0    1    1    0
[10,]    0    0    0    2    0
[11,]    1    0    0    0    1
[12,]    0    1    0    0    1
[13,]    0    0    1    0    1
[14,]    0    0    0    1    1
[15,]    0    0    0    0    2

C++ 中是否有任何现有的实现?

4

2 回答 2

2

递归版本

这是一个递归解决方案。您有一个序列a,您可以在其中跟踪已设置的数字。每个递归调用将在循环中为这些元素之一分配有效数字,然后为列表的其余部分递归调用该函数。

void recurse(std::vector<int>& a, int pos, int remaining) {
  if (remaining == 0) { print(a); return; }
  if (pos == a.size()) { return; }
  for (int i = remaining; i >= 0; --i) {
    a[pos] = i;
    recurse(a, pos + 1, remaining - i);
  }
}

void print_partitions(int sum_val, int n) {
  std::vector<int> a(n);
  recurse(a, 0, sum_val);
}

在http://ideone.com/oJNvmu上可以看到概念证明。

迭代版本

您在下面的评论表明存在性能问题。虽然 I/O 很可能会占用您的大部分性能,但这里有一个迭代解决方案,可以避免递归方法的函数调用开销。

void print_partitions(int sum_val, int n) {
  int pos = 0, last = n - 1;
  int a[n]; // dynamic stack-allocated arrays are a gcc extension
  for (int i = 1; i != n; ++i)
    a[i] = 0;
  a[0] = sum_val;
  while (true) {
    for (int i = 0; i != last; ++i)
        printf("%3d ", a[i]);
    printf("%3d\n", a[last]);
    if (pos != last) {
      --a[pos];
      ++pos;
      a[pos] = 1;
    }
    else {
      if (a[last] == sum_val)
        return;
      for (--pos; a[pos] == 0; --pos);
      --a[pos];
      int tmp = 1 + a[last];
      ++pos;
      a[last] = 0;
      a[pos] = tmp;
    }
  }
}

总体思路和打印顺序与递归方法相同。与其维护 counter remaining,不如将所有令牌(或您正在分区的任何令牌)立即丢弃在它们所属的位置,以便打印下一个分区。pos始终是最后一个非零字段。如果这不是最后一个,那么您可以通过从中获取一个令牌pos并将其移动到之后的位置来获得下一个分区。如果它是最后一个,那么你从最后一个位置取出所有标记,找到之前最后一个非零位置并从那里取出一个标记,然后将所有这些标记转储到你拿单的那个位置之后的位置令牌。

演示在http://ideone.com/N3lSbQ运行。

于 2013-07-04T07:05:59.150 回答
1

您可以自己实现:这样的分区由 6 个整数定义0 <= x[0] <= x[1] <= x[2] <= x[3] <= 2;对应行中的值只是差异x[0]-0, x[1]-x[0],x[2]-x[1]等。如果列数 (5) 是固定的,则您有 4 个嵌套循环;事实并非如此,您可以递归地制定问题。

于 2013-07-04T13:27:38.403 回答