【问题标题】:Integer vector compositions of size K (Implementation in C++)大小为 K 的整数向量组合(C++ 中的实现)
【发布时间】:2018-07-03 18:04:58
【问题描述】:

整数 v 的组合是一组 K 个整数,它们的总和为 v(并且顺序很重要)。例如 2 的 3 尺寸组合是:

2 0 0 
1 1 0 
1 0 1 
0 2 0 
0 1 1 
0 0 2 

可以找到一个简单的 C++ 算法来获得这些组合物here:

void print(std::vector<int>& a) {
    std::ostream_iterator<int> i(std::cout, " ");
    std::copy(a.begin(), a.end(), i);
    std::cout << "\n";
}

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);
     }
 }

int main() {
  int v = 2, k = 3;
  std::vector<int> a(k);
  recurse(a, 0, v);
  return 0;
}

但我需要一些更复杂的东西:

我需要找到一个整数向量的组合。也就是说,给定一个向量 v=(v1, v2, v3) 我需要找到它们所有的单独组合,然后创建所有可能的组合。如果 C 是一个矩阵,其中我将 v1 的分区放在第一行,将 v2 的分区放在第二行,将 v3 的分区放在第三行,那么 C 中行f 的总和给出v[f]

例如,大小为 F=2 的向量 (1,2),如果我们设置 K=2,则可以分解为:

# all sets of K vectors such that their sum is (1,2)
C_1 = 1,0   C_2 = 1,0  C_3 = 1,0 C_4 =  0,1   C_5 = 0,1  C_6 = 0,1
      2,0         1,1        0,2        2,0         1,1        0,2

我们的目标是对每个可能的 C 应用一些函数。我如何在 C++ 中做到这一点?我不介意使用生成器、递归或迭代算法,只要它能正常工作(尽可能快)。

Python

使用递归、yielditertools 库在 Python 中的实现非常好

import numpy as np
import itertools

# Generator to yield all K-size compositions of integer n
def findCombiR(n,K):
    if K==1:
        yield [n]
        return

    for i in range(0,n+1):
        for result in findCombiR(n-i,K-1):
            yield [i] + result

# Generator to yield all K-size compositions of a F-length vector
def findCombiR_v(v,K):
    out = []
    for f in range(0, len(v)):
        out.append(findCombiR(v[f],K))

    return out

# Main
####################

v = [1,2]
F = len(v)
K = 2

# C stores F composition generators, one for each element in v.
C = findCombiR_v(v,K)
#"product" combines all possible outputs of the F generators
for c in itertools.product(*C): 
    c = np.reshape(c, (F,K))
    print(c, '\n')

【问题讨论】:

    标签: c++11 recursion generator combinatorics


    【解决方案1】:

    使用递归的解决方案:

    我们知道如何生成整数的所有组合(请参阅问题中的代码)。为了生成表示 F 个整数的所有组合组合的矩阵,我们只需创建整数 f 的所有可能组合,并且每次找到一个新组合时,我们再次调用该算法以找到整数 f+1 的所有可能组合。每次我们在最后一个整数中找到一个组合意味着我们已经完成了一个有效的矩阵 C。

    #include <iostream>
    #include <armadillo>
    
    using namespace arma;
    
    void recursevec(arma::ivec v, arma::imat& C, int f, int pos, int remaining) {
    
        // If there is no remaining left, we completed a new composition for v[f]
        if (remaining == 0) { 
    
            // If elements in v left, get the combinations of v[f+1]
            if(f < (C.n_rows-1)){
                recursevec(v, C, f+1, 0, v[f+1]);
                return;
            } 
            // If last f, then we are done and we completed a new C
            else {
                std::cout << C << std::endl;
                return;
            }
        }
    
        // If position pointer got out of the vector, 
        // then there is nothing to do
        if (pos == C.n_cols) { return; }
    
        // Else, continue allocating the remaining in all possible ways
        for (int i = remaining; i >= 0; --i) {
            C(f, pos) = i;
            recursevec(v, C, f, pos + 1, remaining - i);
        }
    }
    
    // Test vector compositions
    int main() {
      arma::ivec v = {1,2};
      int F = v.size();
      int K = 2;
      arma::imat C(F,K);
      recursevec(v, C, 0, 0, v[0]);
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-19
      • 2021-04-09
      • 1970-01-01
      • 2023-04-02
      • 2011-10-28
      • 1970-01-01
      相关资源
      最近更新 更多