• 搜索入门练习题2 全排列 题解


    题目出处:课程=>搜索1=>题目A

    题目描述

    给定一个正整数 (n) ,按照递增顺序打印数字 (1)(n) 的所有排列。

    输入格式

    一个整数 (n(1 le n le 7))

    输出格式

    按照递增顺序输出 (n) 个数的所有排列,每行代表一组排列, (n) 个数两两之间有一个空格分隔。

    样例输入

    3
    

    样例输出

    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1
    

    问题分析

    这是一道搜索的题目。
    我们知道搜索就是状态到状态之间的转换,其本质是使用递归的方式进行了枚举(注:这句话是非官方解释,不过很便于理解,所以大家先期就这么理解就好)。
    这道题目可以用枚举做,但是用枚举做会编写大量的重复代码,所以我们这边使用深度优先搜索来解决。
    我们可以开一个 ans[] 数组, ans[id] 用于表示我的当前组合的第 i 个数,然后我开一个函数 void f(int id) 用于表示我当前正准备在组合的第 id 个位置放一个数,然后我只需要从 1 到 n 去遍历一个数 i ,看看 i 能不能放在第 id 个位置(即能否将 ans[id] 设为 i)。
    在第 id 个位置能放 i ,当且仅当:ans[1]ans[id-1] 中的元素都不为 i,即 i 还没有放过。
    这样,当我们的 f(id) 遍历到 id>n 时,就证明找到了一种排列,输出即可。
    实现代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int n, ans[8];  // ans[i]表示当前排列的第i个数是啥
    void f(int id) {    // 用于在ans[]数组的第id个位置放数
        if (id > n) {   // 边界条件,说明n个数的一个排列找到了
            for (int i = 1; i <= n; i ++)
                cout << (i > 1 ? " " : "") << ans[i];
            cout << endl;
            return; // 输出后返回,不需要继续进行判断了
        }
        for (int i = 1; i <= n; i ++) { // 尝试在ans[id]放i
            bool flag = true;
            for (int j = 1; j < id; j ++)
                if (ans[j] == i) {  // 说明ans[]数据的第j个位置已经放过i了
                    flag = false;
                    break;
                }
            if (flag) { // flag为true说明i可以放
                ans[id] = i;
                f(id+1);    // 递归地放下一个位置
            }
        }
    }
    int main() {
        cin >> n;
        f(1);
        return 0;
    }
    

    补充知识

    这里我会在讲解另外一个实现全排列的方案,但是这种方法并不是使用搜索来实现的,而是每次将当前的这个排列转换成它的下一个排列。比如:1 2 3 4 转换一次会变成 1 2 4 3 ,再转换一次会变成 1 3 2 4,如是循环……
    大家可以手动来实现这个程序的编写,但是我们这里先使用 algorithm 库提供给我们的现成的函数——next_permutation
    比如,给我们一个数组 a[5] = {1, 2, 3, 4, 5},我们只需要执行一遍 next_permutation(a, a+5),这个数组 a[] 当中的值就会变成它的下一个全排列 {1, 2, 3, 5, 4}
    并且,next_permutation 的返回值是 bool 类型的,如果当前的排列有下一个排列,调用它会返回 true ,同时将当前排列转成下一个排列,如果当前排列已经是全排列里面的最后一个排列了(例如当 a[5]={5, 4, 3, 2, 1}就已经是全排列里面的最后一个排列了),它会返回 false
    使用 next_permutation 函数解决全排列问题的代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int n, a[] = { 1, 2, 3, 4, 5, 6, 7 };
    void output() {
        for (int i = 0; i < n; i ++)
            cout << (i ? " " : "") << a[i];
        cout << endl;
    }
    int main() {
        cin >> n;
        do output(); while (next_permutation(a, a+n));
        return 0;
    }
    

    思考一下:为什么我的代码里面使用了 do...while 循环,而不是 while 循环。

  • 相关阅读:
    java8
    java8
    java8
    java8
    java8
    java8
    java8
    java8
    GUC-13 生产者和消费者案例-旧
    GUC-14 ForkJoin
  • 原文地址:https://www.cnblogs.com/zifeiynoip/p/11450698.html
Copyright © 2020-2023  润新知