C++STL中全排列函数next_permutation&手动计算全排列递归方法

next_permutation函数

函数原型:

#include <algorithm>
bool next_permutation(iterator start,iterator end)
//当当前序列不存在下一个排列时,函数返回false,否则返回true。

函数介绍:
next_permutation(start,end):求的是当前排列的下一个排列
prev_permutation(start,end):求的是当前排列的上一个排列
注意:
这里的“前一个”和“后一个”,我们可以把它理解为序列的字典序的前后,
严格来讲,就是对于当前序列pn,他的下一个序列pn+1满足:
不存在另外的序列pm,使pn<pm<pn+1.
(1) int 类型的next_permutation

int main()
{
 int a[3];
a[0]=1;a[1]=2;a[2]=3;
 do
{
cout<<a[0]<<"
"<<a[1]<<"
"<<a[2]<<endl;
} while (next_permutation(a,a+3)); //参数3指的是要进行排列的长度
//如果存在a之后的排列,就返回true。如果a是最后一个排列没有后继,返回false,每执行一次,a就变成它的后继

输出:

1 2 3

1 3 2

2 1 3

2 3 1

3 1 2

3 2 1

如果改成 while(next_permutation(a,a+2));
则输出:

1 2 3

2 1 3

只对前两个元素进行字典排序

显然,如果改成 while(next_permutation(a,a+1)); 则只输出:1 2 3

排列本来就是最大的了没有后继,则next_permutation执行后,会对排列进行字典升序排序,相当于循环

 int list[3]={3,2,1};
next_permutation(list,list+3);
cout<<list[0]<<"
"<<list[1]<<"
"<<list[2]<<endl;
//输出: 1 2 3

注意:
next_permutation()在使用前需要对欲排列数组按升序排序,否则只能找出该序列之后的全排列数。
比如,如果数组num初始化为2,3,1,那么输出就变为了:231,312,321
可以自己用一下的代码试一下,next_per这个函数的

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int num[3]={2,3,1}; //{2,1,3};//{1,2,3};
    do
    {
        cout<<num[0]<<" "<<num[1]<<" "<<num[2]<<endl;
    }
    while(next_permutation(num,num+3));
    return 0;
}

(此外,next_permutation(node,node+n,cmp)可以对结构体num按照自定义的排序方式cmp进行排序。—我暂时还用不到)

(参考:https://blog.csdn.net/ac_gibson/article/details/45308645 & http://blog.sina.com.cn/s/blog_9f7ea4390101101u.html)

递归回溯打印全排列2法

例题:
打印全排列问题:
给定一个数n,要求打印123…n的所有全排列.例如n=4,则所有的全排列为:
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2

4 1 2 3
一共4!=24个.

递归回溯加交换

深搜特点:先纵后横,递归是一个套路
(蓝桥杯2015-5特别典型)


或者这样看:

按照箭头方向走

#include<iostream>
using namespace std; //思考:n个开关 和 1个灯 串联,现在已经知道了有k个开关是没有合上的,k的具体值不知道,请尝试把灯点亮.
int tot;//排列数
void swap(int &a,int &b)
{
    int temp = a;
    a = b;
    b = temp;
}
void f(int a[],int n,int k)
{
    if(k==n)
    {
        tot ++;
        for(int i=0; i<n; i++)   cout << a[i] << " ";
        cout << endl;
    }
    for(int i=k; i<n; i++) //当前位置为k,依次和后面的位置交换
    {
        swap(a[k],a[i]);
        f(a,n,k+1);
        swap(a[k],a[i]);//回溯
    }
}
int main()
{
    int n;
    cout << "请输入n:";
    cin >> n;
    int *a = new int[n];
    for(int i=0; i<n; i++)  a[i] = i + 1; //对数组a初始化
    tot = 0;
    f(a,n,0);
    cout << "排列数为:" << tot << endl;
    return 0;
}

递归回溯加选择

思路:取数组a[],从a[1]开始到a[n],从1~n这n个数中选择一个数放在a[1],再选择下一个数,放在下一位a[2]…选过的数字标记为[选过],并且采用递归+回溯的方法进行.

#include<iostream>
using namespace std;
int n;
int a[101];//记录排列
int vis[101];//标记数组
int tot;//排列数
void f(int k)//k为当前位置
{
    if(k==n+1)//K=n+1说明a[n]处的元素已经选完了,此次递归可以结束,打印排列
    {
        tot ++;
        for(int j=1; j<=n; j++)   cout << a[j] << " ";
        cout << endl;
    }
    for(int i=1; i<=n; i++) //从1~n中选择一个数
    {
        if(vis[i]==0)//如果没有选择过
        {
            a[k] = i;//选择它,并且放到第i位置
            vis[i] = 1;//标记为已经选择过该元素
            f(k+1);//进行递归
            vis[i] = 0;//回溯
        }
    }
}
int main()
{
    cout << "请输入n:";
    cin >> n;
    for(int i=1; i<=n; i++)
        vis[i] = 0;
    f(1);
    cout << "排列数为:" << tot << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值