全排列问题(输入整数N,生成从1~N所有整数的全排列)

【问题描述】输入整数N( 1 <= N <= 10 ),生成从1~N所有整数的全排列。

【输入形式】输入整数N。

【输出形式】输出有N!行,每行都是从1~N所有整数的一个全排列,各整数之间以空格分隔。各行上的全排列不重复。输出各行遵循"小数优先"原则, 在各全排列中,较小的数尽量靠前输出。如果将每行上的输出看成一个数字,则所有输出构成升序数列。具体格式见输出样例。

【样例输入1】1

【样例输出1】1

【样例说明1】输入整数N=1,其全排列只有一种。

【样例输入2】3

【样例输出2】 各输出按字典排序

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

可以用回溯算法来解决,排列属于回溯算法解决的范畴

回溯算法?即回溯搜索法。

1.一种搜索方式。回溯是递归的副产品,只要有递归就会有回溯。
2.回溯法并不高效。因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改变不了回溯法就是穷举的本质。既然回溯算法效率这么底下,为什么还要用回溯算法呢?这是因为我们在求解问题当中,一些问题用暴力求解就不错了,很难用高效的算法求出。
3.如何理解?
回溯算法解决的问题都可以抽象为树形结构。因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成的树的深度。递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

下面的图可以很好的描述了

本题的树形结构

可以看出叶子节点,就是我们要的结果
那么什么时候,算是到达叶子节点呢?
当收集元素的数组path的大小达到和nums数组一样大的时候,说明找到了一个全排列,也表示到达了叶子节点。

#include<iostream>
#include<algorithm>
using namespace std;
const int N=10;
bool used[N];//用来判断1-n个数是否已经被选。true表示已经被选,false反之
int path[N];//用来记录1-n个位置选的是哪个数
int n;

void dfs(int m)
{
   if(m>n){//当n个位置确定之后开始打印结果
    for(int i=1;i<=n;i++){
        cout<<path[i]<<" ";
    }
    cout<<endl;
    return;
   }
   for(int i=1;i<=n;i++){
    if(!used[i])//如果这个数没有被选
    {
        used[i]=true;//选择这个数并打上标记
        path[m]=i;//记录
        dfs(m+1);//开始枚举下一个位置
        used[i]=false;//恢复现场
    }
   }
}

int main()
{
    cin>>n;
    dfs(1);//从第一个位置开始遍历
    return 0;
}

还有其他的方法,用python的内置函数itertools.permutations,会更简便一些。

itertools.permutations(a, b) 连续返回由a元素[生成的长度为b的全排列组合

s=[1,2,3]

itertools.permutations(s,3)

# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC

# permutations(range(3)) --> 012 021 102 120 201 210

如果考试写程序建议用python

import itertools
n = int(input())
s = []
for i in range(1, n + 1):
    s.append(i)

num = list(itertools.permutations(s, n))
for ch in num:
    for c in ch:
        print(c,end='')
    print()

函数用法,再如如下示例

import itertools

sum = 0
a=[1, 2, 3, 4, 5]

for i in itertools.permutations(a,2):
    print(i)
    sum += 1
print(sum)

b = list(itertools.permutations(a, 2))
print(b)
print(len(b))

输出

(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 1)
(2, 3)
(2, 4)
(2, 5)
(3, 1)
(3, 2)
(3, 4)
(3, 5)
(4, 1)
(4, 2)
(4, 3)
(4, 5)
(5, 1)
(5, 2)
(5, 3)
(5, 4)
20
[(1, 2), (1, 3), (1, 4), (1, 5), (2, 1), (2, 3), (2, 4), (2, 5), (3, 1), (3, 2), (3, 4), (3, 5), (4, 1), (4, 2), (4, 3), (4, 5), (5, 1), (5, 2), (5, 3), (5, 4)]
20

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值