【发布时间】:2012-03-22 01:51:52
【问题描述】:
我正在尝试实现一个类,该类将在给定元素数量和组合大小的情况下生成所有可能的无序 n 元组或组合。
换句话说,当调用这个时:
NTupleUnordered unordered_tuple_generator(3, 5, print);
unordered_tuple_generator.Start();
print() 是在构造函数中设置的回调函数。 输出应该是:
{0,1,2}
{0,1,3}
{0,1,4}
{0,2,3}
{0,2,4}
{0,3,4}
{1,2,3}
{1,2,4}
{1,3,4}
{2,3,4}
这是我目前所拥有的:
class NTupleUnordered {
public:
NTupleUnordered( int k, int n, void (*cb)(std::vector<int> const&) );
void Start();
private:
int tuple_size; //how many
int set_size; //out of how many
void (*callback)(std::vector<int> const&); //who to call when next tuple is ready
std::vector<int> tuple; //tuple is constructed here
void add_element(int pos); //recursively calls self
};
这是递归函数的实现,Start()只是一个启动函数,具有更简洁的接口,它只调用add_element(0);
void NTupleUnordered::add_element( int pos )
{
// base case
if(pos == tuple_size)
{
callback(tuple); // prints the current combination
tuple.pop_back(); // not really sure about this line
return;
}
for (int i = pos; i < set_size; ++i)
{
// if the item was not found in the current combination
if( std::find(tuple.begin(), tuple.end(), i) == tuple.end())
{
// add element to the current combination
tuple.push_back(i);
add_element(pos+1); // next call will loop from pos+1 to set_size and so on
}
}
}
如果我想生成恒定 N 大小的所有可能组合,可以说大小为 3 的组合:
for (int i1 = 0; i1 < 5; ++i1)
{
for (int i2 = i1+1; i2 < 5; ++i2)
{
for (int i3 = i2+1; i3 < 5; ++i3)
{
std::cout << "{" << i1 << "," << i2 << "," << i3 << "}\n";
}
}
}
如果N不是常数,则需要一个模仿上述的递归函数 通过在其自己的框架中执行每个 for 循环来发挥作用。当 for 循环终止时, 程序返回上一帧,也就是回溯。
我总是遇到递归问题,现在我需要将它与回溯结合以生成所有可能的组合。我在做什么错的任何指示?我应该做什么或我忽略了什么?
P.S:这是一项大学作业,其中还包括对有序的 n 元组做同样的事情。
提前致谢!
/////////////////////////////////////// /////////////////////////////////////////////p>
只是想跟进正确的代码,以防万一其他人想知道同样的事情。
void NTupleUnordered::add_element( int pos)
{
if(static_cast<int>(tuple.size()) == tuple_size)
{
callback(tuple);
return;
}
for (int i = pos; i < set_size; ++i)
{
// add element to the current combination
tuple.push_back(i);
add_element(i+1);
tuple.pop_back();
}
}
对于有序 n 元组的情况:
void NTupleOrdered::add_element( int pos )
{
if(static_cast<int>(tuple.size()) == tuple_size)
{
callback(tuple);
return;
}
for (int i = pos; i < set_size; ++i)
{
// if the item was not found in the current combination
if( std::find(tuple.begin(), tuple.end(), i) == tuple.end())
{
// add element to the current combination
tuple.push_back(i);
add_element(pos);
tuple.pop_back();
}
}
}
感谢 Jason 的详尽回复!
【问题讨论】:
-
您可以将它们作为参数传递给递归函数,而不是将到目前为止的结果存储在成员变量中。这可能有助于弄清楚逻辑。
-
作业要求我存储它们,但也许它会帮助我更好地理解它。谢谢你的建议,我试试看。
-
另外,
pos只是你的tuple向量的大小,所以你应该改用tuple.size()。 -
@howardh ,您使用
tuple.size()是对的,感谢您指出这一点
标签: c++ recursion combinations backtracking