深度优先搜索——回溯

在之前的搜索没居中,我们并没有考虑选入的物品的排列顺序,但在一些题目中,会要求考虑给定数字或物品的排列,这种排列可以是在n个中符合要求的全排列,也可以是在n中找到长度为k的排列。
如果使用我们之前的搜索方法,我们会发现难以用参数标记原数组中的数字选取情况,那么我们就需要一个全局的布尔数组,帮助我们标记哪些数字已经被选入了排列。另一方面,由于我们使用了这样的去安居标记数组,那么必须要用到回溯技巧,在这个分支搜索结束后,将标记数组还原
若要输出 n 个数字全排列,在 dfs 数组中需要的参数需要包含已经选入的数字,在选取当前位数字后进行搜索后,要注意进行回溯
dep表示枚举到第dep为,如果放入后再判断数字是否被用过就太慢了,所以可以在放入前就先判断,如果没有用过,那么当前这个数在标记数组里就应该改为true(用过),当前数组当前这位是这个数字,然后枚举到下一位,最后要回溯,即标记数组这个数字改回false(没用过),由于一直在从小往大找数字,所以最后得到i的结果也一定是字典序

代码示例:

#include 
using namespace std;
const int N = 20;
int n;
int per[N];
bool vis[N];
void dfs (int dep) {
    if(dep==n){
        for(int i=0;i<n;i++){
            cout<<per[i]<<" ";
        }
        cout<<endl;
        return;
    }
    for(int i=1;i<=n;i++){
        if(vis[i]){
            continue;
         }
        per[dep]=i;
        vis[i]=true;
        dfs(dep+1);
        vis[i]=false;
    }
}

int main()
{
    cin >> n;
    dfs(0);
    return 0;
}

如通过要输出n个数字的k排列,我们可以在之前的代码上进行一些小修改。就是当我们选取到k个数字时就应该停止继续搜索的过程。

示例代码:

#include 
using namespace std;
const int N = 20;
int n, k;
int per[N];
bool vis[N];
void dfs (int dep) {
    if(dep==k){
        for(int i=0;i<k;i++){
            cout<<per[i]<<" ";
        }
        cout<<endl;
        return;
    }
    for(int i=1;i<=n;i++){
        if(vis[i]){
            continue;
        }
        per[dep]=i;
        vis[i]=true;
        dfs(dep+1);
        vis[i]=false;
    }
}

int main()
{
    cin >> n >> k;
    dfs(0);
    return 0;
}

你可能感兴趣的:(深搜dfs与广搜bfs,深度优先,算法,c++)