题解:洛谷 P1706 全排列问题
【题目来源】
洛谷:P1706 全排列问题 - 洛谷(luogu.com.cn)
【题目描述】
按照字典序输出自然数 \(1\) 到 \(n\) 所有不重复的排列,即 \(n\) 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。
【输入】
一个整数 \(n\)。
【输出】
由 \(1∼n\) 组成的所有不重复的数字序列,每行一个序列。
每个数字保留 \(5\) 个场宽。
【输入样例】
3
【输出样例】
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
【核心思想】
-
问题分析:给定 \(n\),要求输出 \(1\) 到 \(n\) 的所有全排列,按字典序输出,每个数字占 5 个场宽。这是经典的全排列生成问题,可以使用深度优先搜索(DFS)枚举所有排列,通过标记数组记录已使用的数字,避免重复。
-
算法选择:
- DFS + 回溯:递归函数
dfs(step)表示当前正在填充第step个位置(从 0 或 1 开始)。若step == n,则输出当前排列。否则,循环尝试将每个未使用的数字放入当前位置,标记后递归,回溯时取消标记。 - 输出格式:使用
setw(5)设置每个数字宽度为 5。
- DFS + 回溯:递归函数
-
关键步骤:
- 读入:读取 \(n\)。
- DFS:
dfs(step):- 若
step == n,输出a[0..n-1](或a[1..n]),返回。 - 循环
i从 1 到 \(n\):- 若
book[i] == 0:a[step] = i,book[i] = 1。- 递归
dfs(step+1)。 book[i] = 0(回溯)。
- 若
- 若
- 输出:使用
cout << setw(5) << a[i]。
-
时间/空间复杂度:
- 时间复杂度:\(O(n! \times n)\),\(n\) 通常较小(\(n \le 9\)),完全可行。
- 空间复杂度:\(O(n)\)。
-
DFS 与全排列:
- 回溯思想:通过标记数组记录已用数字,递归填下一个位置,递归返回后撤销标记,尝试其他数字。
- 字典序:由于循环从小到大尝试数字,生成的排列自然按字典序排列。
- 适用场景:全排列生成是 DFS 最经典的应用之一。
【解题思路】


【算法标签】
普及- #DFS-一维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, a[10], book[10] = {0}; // 定义全局变量:n-排列长度,a-存储当前排列,book-标记数组
// 深度优先搜索生成全排列
void dfs(int step)
{
// step: 当前正在填充的位置索引(从0开始)
// 终止条件:已填满整个排列
if (step == n)
{
// 输出当前排列(每个数字占5位宽度)
for (int i = 0; i < n; i++)
cout << setw(5) << a[i];
cout << endl;
return;
}
// 尝试所有可能的数字(1到n)
for (int i = 1; i <= n; i++)
{
// 如果数字i未被使用
if (book[i] == 0)
{
a[step] = i; // 将数字i放入当前位置
book[i] = 1; // 标记数字i为已使用
dfs(step + 1); // 递归处理下一个位置
book[i] = 0; // 回溯,取消数字i的标记
}
}
}
int main()
{
cin >> n; // 输入排列长度n
dfs(0); // 从第0个位置开始生成排列
return 0;
}
#include <bits/stdc++.h>
using namespace std;
// 全局变量声明
int n; // 排列长度(1到n的全排列)
int a[10]; // 存储当前生成的排列(索引1到n)
int book[10] = {0}; // 标记数组,记录数字是否已使用(0未使用,1已使用)
// 深度优先搜索函数
void dfs(int step)
{
// step表示当前正在处理的位置(从1开始)
// 终止条件:当step超过n时,说明已经生成了一个完整的排列
if (step == n + 1)
{
// 输出当前排列(每个数字占5位宽度)
for (int i = 1; i <= n; i++)
cout << setw(5) << a[i]; // 格式化输出
cout << endl; // 换行
return; // 返回上一层递归
}
// 尝试将每个数字放入当前位置
for (int i = 1; i <= n; i++)
{
// 检查数字i是否未被使用
if (book[i] == 0)
{
a[step] = i; // 将数字i放入当前位置
book[i] = 1; // 标记数字i为已使用
dfs(step + 1); // 递归处理下一个位置
// 回溯操作
a[step] = 0; // 清除当前位置的值(可省略)
book[i] = 0; // 取消数字i的标记
}
}
}
int main()
{
cin >> n; // 输入排列长度n
dfs(1); // 从第1个位置开始生成排列
return 0;
}
【运行结果】
3
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
浙公网安备 33010602011771号