算法设计——全排列算法递归
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
公式:全排列数f(n)=n!(定义0!=1)
本文要讨论的算法要完成的任务是:给定一个数组,输出其所有的全排列结果。要求可以概括为两点:
1 输出该数组所有的全排列结果
2 任意两个全排列是不同的,即任意两个全排列中n个数字排列的顺序不能相同
其实核心思想就是枚举数组中每个位置的数字,而难点就是如何有序地枚举数组每个位置的数字而做到既全面又不重复。
首先我们以这个数组为a={1,2,3}为例,要找到它所有的全排列,这里我们用a[0],a[1],a[2]来表示这个数组中的第一、第二、第三个位置的数值,当前的数组各个位置的值为a[0]=1,a[1]=2,a[2]=3。于是算法可以分为以下几步来完成:
对a[0]的位置用1,2,3分别来替换,得到3个子序列
由于a[0]位置能取的所有的值的情况已经枚举完毕了,所以我们再对这3个子序列中a[1]位置所有能取的值再进行枚举。
到这里时,所有的子序列a[0]和a[1]都已经确定了,所以a[2]就自然已经确定了,只需要输出即可。图示如下:
下面开始写算法
#include <iostream>
#include <stdio.h>
#include <algorithm>
//全排列算法问题
using namespace std;
void swap(int &a , int &b)//实现两个数值的交换
{
int temp;
temp = a;
a = b;
b = temp;
}
//全排列递归算法
void Perm(int list[] , int k ,int m)
{
//list 数组存放排列的数,K表示层 代表第几个数,m表示数组的长度
if(k==m)
{
//K==m 表示到达最后一个数,不能再交换,最终的排列的数需要输出;
for(int i=0 ;i<=m ;i++)
cout<<list[i];
cout<<endl;
}
else{
for(int i=k;i<=m;i++)
{
swap(list[i],list[k]);
Perm(list,k+1,m);
swap(list[i] , list[k]);
}
}
}
int main()
{
int num;cin>>num;//输入数的长度
int tot[num];
for(int i=0;i<num;i++)
cin>>tot[i];//输入需要全排列的数值
//本代码统一按照从小到大的排序方式输出
sort(tot,tot+num);//先将输入的数组按照从小到大排序
Perm(tot,0,num-1);
return 0;
}
这样就完成了全排列的算法代码。但是这并不符合要求。
当我们输入1 1 1时他同样会进行全排列的排序,显然我们需要对这中情况进行特殊的处理
这里只说名下想法:
我们可以设置一个结构体 struct 然后 设置 vector<node> s;
最后使用集合去除重复的部分,然后输出即可
然后我们用一下C++的STL库
#include<iostream>
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
int main()
{
int num[5];
for(int i=1;i<=4;i++)
num[i]=i;
int ans=0;
do//全排列
{
for(int i=1;i<=4;i++)
cout<<num[i]<<" ";
cout<<endl;
ans++;
}while(next_permutation(num+1,num+1+4));
cout<<ans<<endl;
return 0;
}