【问题描述】
尝试用递归的方法:先输出所有以1开头的排列,然后输出以2开头的排列,…一直到输出完以9开头的排列。
【伪代码】
void print_permutation(序列 A,集合 S)
{
if(S为空) 输出序列A;
else 按照从小到大的顺序依次考虑S的每个元素V
{
print_permutation(在A的末尾添加V后得到的新序列,S-{V});
}
}
【代码】
由于集合S可以用序列A表示出来–遍历1-N的所有数,只要A中没有出现的元素即可使用,因此可以不使用S保存剩余元素的集合。由于数组的大小未知,因此参数应该包括数组大小n。由于需要确定递归的终止条件,也就是将最后一个元素排列好即可终止,因此还需要传参cur来确定当前的位置。
void print_permutation(int n,int *a,int cur)
{
if (cur == n)
{
for (int i = 0;i < n;i++) cout << a[i];
cout << endl;
}
else for (int i = 1;i <= n;i++){
int flag = 1;
for (int j = 0;j < cur;j++)
if (i == a[j]) flag = 0; //如果i在a[0]~a[cur-1]中出现过就不再选
if (flag) {
a[cur] = i;
print_permutation(n, a, cur + 1);//递归调用
}
}
}
改进
以上代码和思路来自书中,由于是最初的教程未引入标记变量vis,因此时间复杂度较高,下面给出更简单的版本。
使用 vis[maxn] 来标记使用过的数值,这样就无需再依次判断 a[0] 到 a[cur-1] 了。
【代码】
void DFS(int n,int *a,int cur)
{
if (cur == n)
{
for (int i = 0;i < n;i++) cout << a[i];
cout << endl;
}
else for (int i = 1;i <= n;i++){
if (!vis[i]) {
vis[i] = 1; //标记为走过
a[cur] = i;
DFS(n, a, cur + 1);//递归调用
vis[i] = 0;
}
}
}
本文详细介绍了如何使用递归方法实现全排列算法,通过两种不同的优化策略,一是避免重复选择已使用的元素,二是引入标记变量减少不必要的检查,提高了算法效率。
1382

被折叠的 条评论
为什么被折叠?



