有人可以解释这个代码,该代码生成给定集合的所有可能置换吗?

问题描述

我在 竞争性程序员手册也可以做到这一点,但我正努力理解其背后的逻辑。
它指出:

像子集一样,可以使用递归来生成排列。以下 函数搜索遍历集合{0,1,...,n¡1}的排列。的 函数构建包含该置换的向量置换,并且 当调用不带参数的函数时,搜索开始。

void search() {
    if (permutation.size() == n) {
        // process permutation
    } else {
        for (int i = 0; i < n; i++) {
            if (chosen[i]) continue;
            chosen[i] = true;
            permutation.push_back(i);
            search();
            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();
        }
    }
}

直觉可能是search()是“以所有可能的方式完成当前部分构造的置换并处理所有置换”。

如果它已经完成,我们只需要处理一个可能的排列。 如果没有,我们可以首先以各种可能的方式选择第一个数字 ,然后针对每种方式,递归地完成排列。

,

我会尝试给你一些直觉。主要思想是 回溯 。您基本上会构建一个解决方案,直到遇到死胡同。当您遇到死胡同时,请回到最后一个位置,在这里您可以执行与上次不同的操作。让我来看一下我为region绘制的模拟。

enter image description here

首先,你什么都没有。先走n = 3,然后走1再走2。您现在无处可去,即 Dead End 。您将打印当前的3排列,您现在要做什么?回到123,因为您知道这次可以走1可以走另一条路。那么,您这次以同样的方式得到什么? 3使用1还能执行其他操作吗? 。现在回到一无所有,重新开始同样的事情,现在使用132。您现在明白了吧?

对于代码中发生的相同情况:

2