如果这个问题有正式的名称(或者这是重复的,我还没有找到正确的问题),那么指出我应该搜索的内容也将不胜感激!但是,我还没有找到任何关于这个特定问题的讨论或方法。
我试图让问题尽可能简单,如果有更多细节可以让我知道。
假设我们有四个int的随机长度向量:
std::vector<int> v1 {1, 7, 5, 2};
std::vector<int> v2 {4, 2, 1};
std::vector<int> v3 {1, 9, 4, 6, 4, 1, 2};
std::vector<int> v4 {9, 4};
在这四个向量中,我需要生成每个可能的组合,其中我们一次只从每个源向量(v1-v4)中选择一个int。结果应该是我们从源向量中生成每个可能的N长度数,其中N =源向量的数量(在这种情况下为4)。
很容易生成一些可能的组合,例如只选择每个源向量中的第一个数字:
1 4 1 9
选择每个源向量的最后一个数字:
2 1 2 4
我被困的地方正在产生每一种可能的组合。我需要通过组合来自4个源向量中的每一个的一个int来创建每个可能的N长度数。
谢谢!
答案 0 :(得分:1)
以下是任意数量的输入向量的答案:
将索引配置视为数字,由不同数字系统中的数字组成。 然后考虑计算一组索引,就像在某个数字系统中计算常规数字一样。 对于四个大小为3 5 2 5的向量,例如,索引集0 2 1 4将导致0 3 0 0。
对于下面的代码,我假设你的向量是在另一个向量中给出的,即vector<vector<int> >
这里有一个索引类:
class Indices {
private:
vector<size_t> indices;
vector<size_t> maximal_sizes;
bool _max_reached;
public:
Indices(const vector<vector<int> >& vectors) : indices(vectors.size(), 0), maximal_sizes(vectors.size()), _max_reached(false) {
for(size_t i = 0; i < vectors.size(); i++){
maximal_sizes[i] = vectors[i].size();
}
}
const size_t& operator[] (const size_t i) const { return indices[i]; }
bool max_reached() const { return max_reached; }
void count_up() {
size_t current = 0;
while(current < indices.size()){
indices[current]++;
if(indices[current] >= maximal_sizes[current]){
indices[current] = 0;
current++;
} else {
return;
}
}
_max_reached = true;
}
}
(将其拆分为标题和来源)
并像
一样使用它inline void print(const vector<vector<int> >& vectors, const Indices& indices){
for(size_t i = 0; i < vectors.size(); i++){
cout << vectors[i][Indices[i]] << " ";
}
cout << endl;
}
void all_combinations(const vector<vector<int> >& vectors){
Indices indices(vectors);
while(not indices.max_reached()){
print(vectors, indices);
indices.count_up();
}
}
(可能不是完全没有这样的功能,但是你明白了。另外,Indices
我认为不够具有描述性,但现在想不出一个好的短名称.max_reached机制是有点烦我,看起来并不优雅。如果有人有改进的想法,我很乐意听到。)
答案 1 :(得分:1)
您确实在描述集合的Cartesian product。就像普通的数字产品一样,这是对两件事的操作,但它可以连续应用于两件以上的事情:
A x B x C x D = A x(B x(C x D))
这种结构是理解问题的关键。您可以将其分解为每个仅涉及两组的递归子问题。这样你就可以处理任意数量的集合。
解决问题的程序也可以是递归的,也可以是迭代的。以下是使用由vector<int>
表示的lists集合的半优化递归解决方案。给出一组集
A,......
它计算两件事的笛卡尔乘积:A和其余集合的笛卡尔乘积:
A x(...)
您可以重新排列此过程以从基本情况开始向上,即((D x C)x B)x A.这样您就可以使用循环而不是递归调用。但是考虑问题的递归结构是组织思想的好方法。
void cartesian_product( list< vector<int> > sets, list< vector<int> >& product) {
if ( sets.empty() )
return;
// get first set
auto& s = sets.front();
// base case
if ( ++begin( sets ) == end( sets ) ) {
for ( auto k : s ) {
product.push_back( { k } );
}
return;
}
// get cartesian product of the rest of the sets
cartesian_product( list< vector<int> >( ++begin( sets ), end( sets ) ), product );
// make additional copies of product and append each element of first set to them
list< vector<int> > additions;
for ( auto k = ++begin( s ); k != end( s ); ++k ) {
list< vector<int> > ad = product;
for ( auto& x : ad ) {
x.push_back( *k );
}
additions.splice( end( additions ), ad );
}
// append the first element of the first set to the original product
for ( auto& x : product ) {
x.push_back( s.front() );
}
// append the additions to the final product
product.splice( end( product ), additions );
return;
}
以下是该计划的其余部分:
#include <cassert>
#include <iostream>
#include <list>
#include <vector>
using std::vector;
using std::list;
using std::cout;
using std::endl;
void cartesian_product( list< vector<int> > sets, list< vector<int> > &product);
int main( int argc, char *argv[] ) {
list< vector<int> > sets = {
{1, 7, 5, 2},
{4, 2, 1},
{1, 9, 4, 6, 4, 1, 2},
{9, 4}
};
list< vector<int> > product;
cartesian_product( sets, product );
for ( auto& x : product ) {
cout << "{ ";
for ( auto k : x ) {
cout << k << " ";
}
cout << "}" << endl;
}
}