C++的next_permutation函数与排列问题解法

ops/2025/3/4 3:55:16/

在这里插入图片描述
大家好哇^ _ ^

火星人问题(P1088)

一、next_permutation函数解析

1.1 基本定义与特性

next_permutation是C++标准库<algorithm>中的全排列生成函数,其核心功能是按照字典序生成给定序列的下一个排列。函数的两种形式:

bool next_permutation(BidirIt first, BidirIt last);  // 默认使用<比较
bool next_permutation(BidirIt first, BidirIt last, Compare comp); // 自定义比较函数
  • 返回值:存在更大排列时返回true,否则返回false并重置为最小排列12
  • 时间复杂度:O(n),n为序列长度

关键特性:

  1. 必须先将序列排序为最小字典序,才能生成所有排列
  2. 直接修改原序列,生成新排列
  3. 支持自定义比较规则处理特殊顺序(如大小写混合排序)

1.2 典型使用模式

生成全排列的标准模板:

sort(arr, arr+n); // 必须排序
do {// 处理当前排列
} while(next_permutation(arr, arr+n));

二、算法竞赛应用实例

2.1 火星人问题(P1088)

题目本质:给定排列,求其之后第M个字典序排列
核心代码

int main() {int n, m;cin >> n >> m;vector<int> fingers(n);for(int i=0; i<n; i++) cin >> fingers[i];// 直接调用m次生成下一个排列for(int i=0; i<m; i++) next_permutation(fingers.begin(), fingers.end());// 输出结果for(int i=0; i<n; i++) cout << fingers[i] << " \n"[i==n-1];
}

关键点

  • 初始排列不需要排序,题目给定的就是当前排列状态
  • 连续调用m次函数即可得到目标排列

三、排列型DFS的通用模板

当需要处理以下场景时,需手写DFS回溯算法

  1. 元素有重复需要去重(如[1,1,2]的全排列)
  2. 需要剪枝优化时间复杂度
  3. 题目要求输出特定格式(如按层分步输出)

模板题

通用模板代码

vector<vector<int>> res;
vector<int> path;
vector<bool> visited;void dfs(int u, int n) {if(u == n) {res.push_back(path);return;}for(int i=0; i<n; i++) {if(!visited[i]) {path.push_back(nums[i]);  // 选择当前元素visited[i] = true;dfs(u+1, n);              // 递归下一层path.pop_back();          // 回溯visited[i] = false;}}
}// 调用方式:
sort(nums.begin(), nums.end()); // 处理重复元素时需要
visited.resize(nums.size(), false);
dfs(0, nums.size());

与库函数的对比

特性next_permutationDFS回溯
时间复杂度O(n!)O(n!)
空间复杂度O(1)O(n)
处理重复元素需要手动去重可剪枝去重
适用数据规模n≤12n≤10
代码复杂度极低中等

四、实战技巧总结

  1. 字典序的本质:排列的比较规则类似于字符串比较,213 > 132因为首位2>1
  2. 逆序检测:当next_permutation返回false时,说明当前是最大排列,此时序列被重置为升序
  3. 性能优化:当n较大时(如n>12),应避免使用全排列算法,考虑数学方法或动态规划
  4. 特殊排列处理:通过自定义比较函数可实现非标准字典序(如大小写字母混合排序)

选择建议:

当需要按顺序生成排列时,优先考虑next_permutation

当需要剪枝或处理复杂约束时,使用DFS

N较大时(如N>15),必须使用STL函数

通过合理选择库函数与手写算法,可以显著提升排列类问题的解题效率。建议在竞赛中优先使用next_permutation处理小规模数据,遇到需要剪枝或特殊处理的排列问题时再考虑DFS回溯算法


http://www.ppmy.cn/ops/162946.html

相关文章

【Git】Ubuntu 安装 Git Large File Storage(LFS)以及使用 Git LFS 下载

【Git】Ubuntu 安装 Git Large File Storage&#xff08;LFS&#xff09;以及使用 Git LFS 下载 1 安装1.1 使用脚本安装1.2 使用 packagecloud 安装 2 使用2.1 下载 1 安装 1.1 使用脚本安装 参考文档: Link 下载安装包: Link 解压安装包 tar -xzvf git-lfs-linux-amd64-v3.…

大白话虚拟 DOM 原理与 diff 算法的实现机制

虚拟 DOM 原理 啥是虚拟 DOM 想象一下&#xff0c;我们要建一座房子&#xff0c;在真正动手盖之前&#xff0c;先在纸上画一个房子的模型&#xff0c;这个模型就相当于虚拟 DOM。在网页开发里&#xff0c;真实的 DOM 就像那座真正的房子&#xff0c;而虚拟 DOM 就是用 JavaSc…

Vue.js Vue 测试工具:Vue Test Utils 与 Jest

Vue.js Vue 测试工具&#xff1a;Vue Test Utils 与 Jest 在 Vue.js 的开发过程中&#xff0c;编写和执行测试是确保应用质量和稳定性的关键步骤。Vue Test Utils 和 Jest 是 Vue.js 官方推荐的测试工具&#xff0c;二者结合使用&#xff0c;可以高效地进行单元测试和集成测试…

【Linux vi文本编辑器使用指南】

Linux vi文本编辑器使用指南 一、模式切换二、启动与退出三、光标移动&#xff08;命令模式&#xff09;四、编辑文本五、查找与替换六、其他实用命令七、示例流程八、学习建议 Linux系统中的 vi&#xff08;及其增强版 vim&#xff09;是一款功能强大的文本编辑器&#xff0…

【Transformer模型学习】第三篇:位置编码

文章目录 0. 前言1. 为什么需要位置编码&#xff1f;2. 如何进行位置编码&#xff1f;3. 正弦和余弦位置编码4. 举个例子4.1 参数设置4.2 计算分母项4.3 计算位置编码4.4 位置编码矩阵 5. 相对位置信息6. 改进的位置编码方式——RoPE6.1 RoPE的核心思想6.2 RoPE的优势 7. 总结 …

Nginx系列05(负载均衡、动静分离)

目录 Nginx 负载均衡 Nginx 动静分离 Nginx 负载均衡 概念&#xff1a;负载均衡是一种将网络流量分摊到多个后端服务器&#xff08;节点&#xff09;上的技术&#xff0c;以提高系统的可用性、性能和可扩展性。通过负载均衡&#xff0c;Nginx 可以根据一定的算法将客户端请求…

基于SpringBoot+Vue的医院挂号管理系统+LW示例参考

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

React 高阶组件(HOC)

1.React 高阶组件&#xff08;HOC&#xff09; ****1. HOC&#xff08;高阶组件&#xff09;HOC (Higher - Order Component) 定义&#xff1a; 高阶组件是一个接收组件作为参数并返回新组件的函数&#xff0c;用于复用组件逻辑&#xff0c;遵循纯函数特性&#xff08;无副作用…