C++ 有人能给我解释一下这个生成给定集合所有可能置换的代码吗?
我在 竞争对手的《程序员手册》也这么做了,但我很难理解它背后的逻辑。 它指出: 与子集一样,可以使用递归生成置换。以下 函数搜索遍历集合{0,1,…,n{1}的排列。这个 函数构建包含置换的向量置换,并 在调用不带参数的函数时开始搜索。 每个函数调用都会向排列添加一个新元素。选择的阵列 指示排列中已包含哪些元素。如果 置换等于集合的大小,已生成置换。 我似乎无法理解正确的直觉和使用的概念。C++ 有人能给我解释一下这个生成给定集合所有可能置换的代码吗?,c++,algorithm,recursion,set,permutation,C++,Algorithm,Recursion,Set,Permutation,我在 竞争对手的《程序员手册》也这么做了,但我很难理解它背后的逻辑。 它指出: 与子集一样,可以使用递归生成置换。以下 函数搜索遍历集合{0,1,…,n{1}的排列。这个 函数构建包含置换的向量置换,并 在调用不带参数的函数时开始搜索。 每个函数调用都会向排列添加一个新元素。选择的阵列 指示排列中已包含哪些元素。如果 置换等于集合的大小,已生成置换。 我似乎无法理解正确的直觉和使用的概念。 有人能给我解释一下代码在做什么以及背后的逻辑吗?你可以这样分解代码: void search() {
有人能给我解释一下代码在做什么以及背后的逻辑吗?你可以这样分解代码:
void search() {
if (permutation.size() == n) {
// we have a valid permutation here
// process permutation
} else {
// The permutation is 'under construction'.
// The first k elements are fixed,
// n - k are still missing.
// So we must choose the next number:
for (int i = 0; i < n; i++) {
// some of them are already chosen earlier
if (chosen[i]) continue;
// if i is still free:
// signal to nested calls that i is occupied
chosen[i] = true;
// add it to the permutation
permutation.push_back(i);
// At the start of this nested call,
// the permutation will have the first (k + 1)
// numbers fixed.
search();
// Now we UNDO what we did before the recursive call
// and the permutation state becomes the same as when
// we entered this call.
// This allows us to proceed to the next iteration
// of the for loop.
chosen[i] = false;
permutation.pop_back();
}
}
}
直觉可能是,搜索以各种可能的方式完成当前部分构造的排列,并处理所有排列
如果已经完成,我们只需要处理一个可能的排列。
如果没有,我们可以首先以各种可能的方式选择第一个数字,然后,对于其中的每一个,递归地完成排列。您可以像这样拆分代码:
void search() {
if (permutation.size() == n) {
// we have a valid permutation here
// process permutation
} else {
// The permutation is 'under construction'.
// The first k elements are fixed,
// n - k are still missing.
// So we must choose the next number:
for (int i = 0; i < n; i++) {
// some of them are already chosen earlier
if (chosen[i]) continue;
// if i is still free:
// signal to nested calls that i is occupied
chosen[i] = true;
// add it to the permutation
permutation.push_back(i);
// At the start of this nested call,
// the permutation will have the first (k + 1)
// numbers fixed.
search();
// Now we UNDO what we did before the recursive call
// and the permutation state becomes the same as when
// we entered this call.
// This allows us to proceed to the next iteration
// of the for loop.
chosen[i] = false;
permutation.pop_back();
}
}
}
直觉可能是,搜索以各种可能的方式完成当前部分构造的排列,并处理所有排列
如果已经完成,我们只需要处理一个可能的排列。
如果没有,我们可以先用各种可能的方法选择第一个数字,然后,对于其中的每一个,递归地完成排列。我将尝试给你一些直觉。主要的想法是回溯。您基本上构建了一个解决方案,直到面临死胡同。当你面对一条死胡同时,回到最后一个位置,在那里你可以做一些与上次不同的事情。让我浏览一下我为n=3绘制的模拟 首先,你什么都没有。先拿1,然后拿2,再拿3。你现在无处可去,即死胡同。你打印你当前的排列是123你现在做什么?返回到1,因为您知道,通过这次选择3,您可以创建另一条路径。那么这次你用同样的方法得到了什么?132 . 你能用1做更多的事情吗?不。现在回到什么都没有的状态,重新开始同样的事情,现在是2。你现在明白了,对吧 对于代码中发生的相同事情: 无效搜索{ 如果permutation.size==n///死胡同 { //过程置换 } 否则{ 对于int i=0;i
逐个删除当前排列,然后递归生成具有此前缀的剩余元素的所有排列,然后再次删除此级别的当前元素并继续下一个,直到没有更多的元素可供尝试。使用有更好的解决方案:。