简单来说,全排列是指不同元素在不同位置上的所有方案。这是「组合数学」的相关知识。

C++ 提供了独有的 next_permutation() 函数,它在原数组上改变元素排列顺序。

例题 1:力扣 31. 下一个排列

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须 原地 修改,只允许使用额外常数空间。

参考代码
  1. class Solution {
  2. public:
  3. void nextPermutation(vector<int>& nums) {
  4. /* 代码实现:
  5. int i = nums.size() - 2;
  6. while (i >= 0 && nums[i] >= nums[i+1]) i--;
  7. if (i >= 0) {
  8. int j = nums.size() - 1;
  9. while (j >= i && nums[j] <= nums[i]) j--;
  10. swap(nums[i], nums[j]);
  11. }
  12. reverse(nums.begin() + i + 1, nums.end());*/
  13. // 函数实现
  14. next_permutation(nums.begin(), nums.end());
  15. }
  16. };

例题 2:蓝桥 带分数【第四届】【省赛】

这个问题可以看成,数字 1 ~ 9 的所有排列顺序上,枚举两个分割点,得到三个数,验证这三个数是否符合等式。next_permutation() 函数仅在遍历到最后一个排列时返回 false ,配合 do_while 语句可以从第一个排列开始,遍历所有的排列。

参考代码
#include <iostream>
#include <algorithm>
using namespace std;
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int n = 9;
int x;
// 取得 a[] 上下标 [l, r] 组成的数字
int getNum(int l, int r) {
    int ret = 0;
    for (int i=l; i<r; ++i) {
        ret *= 10;
        ret += a[i];
    }
    return ret;
}
// 检查是否使等式成立
bool check(int i, int j) {
    int a = getNum(0, i);
    int b = getNum(i, j);
    int c = getNum(j, n);
    return b % c == 0 && x == a + b / c;
}
int main() {
    cin >> x;
    int ans = 0;
    // 遍历所有排列
    do {
        // 两重 for 枚举两个分割点
        for (int i=1; i<n-1; ++i) {
            for (int j=i+1; j<n; ++j) {
                ans += check(i, j);        // 统计成立的等式数量
            }
        }
    } while (next_permutation(a, a + n));
    cout << ans << endl;
    return 0;
}

你也可以使用 dfs 搜索所有的排列。可是既然有 next_permutation(),为什么不呢。

DFS 实现参考AcWing 1209. 带分数