交换法全排列
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
int n,a[MAX];
void permutation(int pos)
{
if(pos==n)
{
for(int i=0;i<n;i++)
cout<<a[i];
cout<<endl;
return ;
}
for(int i=pos;i<n;i++)//每次以pos为基准 i与其交换
{
swap(a[i],a[pos]);
permutation(pos+1);
swap(a[i],a[pos]);//交换完必须要换回来 不然受上一个状态的影响
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
permutation(0);
}
抽取法全排列
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
int n,a[MAX],b[MAX],vis[MAX]={0};
void permutation(int pos)
{
if(pos==n)
{
for(int i=0;i<n;i++)
cout<<b[i];
cout<<endl;
return ;
}
for(int i=0;i<n;i++)//每次从0开始遍历 访问过就下一个 没有就递归进去
{
if(!vis[i])
{
vis[i]=1;
b[pos]=a[i];
permutation(pos+1);
vis[i]=0;
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
permutation(0);
}
案例:三角形塔(堆积木)
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
int n,a[MAX];
int child[2][6]={{1,3,4,6,7,8},{2,4,5,7,8,9}};
bool check()
{
for(int i=0;i<6;i++)
{
if(a[child[0][i]]<a[i]||a[child[1][i]]<a[i])
return false;
}
return true;
}
void permutation(int pos)
{
if(pos==10)
{
if(check())
{
cout<<" "<<a[0]<<endl;
cout<<" "<<a[1]<<" "<<a[2]<<endl;
cout<<" "<<a[3]<<" "<<a[4]<<" "<<a[5]<<endl;
cout<<a[6]<<" "<<a[7]<<" "<<a[8]<<" "<<a[9]<<endl;
}
return ;
}
for(int i=pos;i<10;i++)//每次以pos为基准 i与其交换
{
swap(a[i],a[pos]);
permutation(pos+1);
swap(a[i],a[pos]);//交换完必须要换回来 不然受上一个状态的影响
}
}
int main()
{
for(int i=0;i<10;i++)//0-9
a[i]=i;
permutation(0);
}
前面两种算法都无法排除一种情况,就是有重复值出现的时候,排列也会反复列举,eg:1 3 4 4
交换法全排列改进算法:
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
int n,a[MAX];
void permutation(int pos)
{
if(pos==n)
{
for(int i=0;i<n;i++)
cout<<a[i];
cout<<endl;
return ;
}
for(int i=pos;i<n;i++)//每次以pos为基准 i与其交换
{
if(i>pos&&a[i]==a[i-1])//相邻的重复数字 i>pos写在前面是为了避免:1.i=0时数组越界 2.i==pos时 是第一次顺序遍历
continue;
swap(a[i],a[pos]);
permutation(pos+1);
swap(a[i],a[pos]);//交换完必须要换回来 不然受上一个状态的影响
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
permutation(0);
}
抽取法全排列改进算法:
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
int n,a[MAX],b[MAX],vis[MAX]={0};
void permutation(int pos)
{
if(pos==n)
{
for(int i=0;i<n;i++)
cout<<b[i];
cout<<endl;
return ;
}
for(int i=0;i<n;i++)//每次从0开始遍历 访问过就下一个 没有就递归进去
{
if(i!=0&&a[i]==a[i-1]&&!a[i-1])//i!=0防止数组越界 !a[i-1]表明数组没有被访问过 说明第一次顺序遍历已经过了
continue;
if(!vis[i])
{
vis[i]=1;
b[pos]=a[i];
permutation(pos+1);
vis[i]=0;
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
permutation(0);
}
next_permutation方法获得全排列
C++ STL 中提供了 std::next_permutation 与 std::prev_permutation 可以获取数字或者是字符的全排列,其中 std::next_permutation提供升序 、 std::prev_permutation提供降序 。说明: next_permutation ,重新排列范围内的元素 [ 第一,最后一个)返回按照 字典序排列 的下一个值较大的排列。返回值:如果有一个更高的排列,它重新排列元素,并返回 true ;如果这是不可能的(因为它已经在最大可能的排列),它按升序排列所有元素,并返回false 。
举个栗子:李白打酒
话说大诗人李白,一生好饮。幸好他从不开车。一天,他提着酒壶,从家里出来,酒壶中有酒 2 斗。他边走边唱:无事街上走,提壶去打酒。逢店加一倍,遇花喝一斗。这一路上,他一共遇到店 5 次,遇到花 10 次,已知最后一次遇到的是花,他正好把酒喝光了。请你计算李白遇到店和花的次序,可以把遇店记为 a ,遇花记为 b 。则: babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。输出:14
解析:
用
1
代表遇到花,
0
代表遇到店。最后一位固定为
1
,前面
14
位必须有
9
个
1
,
5
个
0
。
元素不变,顺序可变,不同的排列顺序对应一种可能的方案,可以将解空间看成是
14
个数的排列问题。 但是存在重复的元素,应该采用可以处理重复元素的全排列方法。
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
int n,a[MAX];
bool check()
{
int s=2;
for(int i=0;i<15;i++)
{
if(a[i]==0)
s*=2;
else
s-=1;
}
return s==0;
}
int main()
{
int i;
for(i=0;i<5;i++)
a[i]=0;
for(i;i<15;i++)
a[i]=1;
i=0;
do{
if(check())
i++;
}while(next_permutation(a,a+14));
cout<<i;
}
举个栗子2:扑克序列
A A 2 2 3 3 4 4 , 一共 4 对扑克牌。请你把它们排成一行。要求:两个 A 中间有 1 张牌,两个 2 之间有 2 张牌,两个 3 之间有 3 张牌,两个 4 之间有 4 张牌。请填写出所有符合要求的排列中,字典序最小的那个。例如: 22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。请通过浏览器提交答案。 “A” 一定不要用小写字母 a ,也不要用 “1” 代替。字符间一定不要留空格。
解析:全排列+条件判断
#include<bits/stdc++.h>
#define MAX 100
using namespace std;
int n;
bool check(char str[])
{
string s(str,str+8);//取str数组的前8个
int a1=s.find('A'),a2=s.rfind('A');//正向反向分别找'A'对应的下标
int b1=s.find('2'),b2=s.rfind('2');
int c1=s.find('3'),c2=s.rfind('3');
int d1=s.find('4'),d2=s.rfind('4');
if(abs(a2-a1)==2&abs(b1-b2)==3&&abs(c1-c2)==4&&abs(d1-d2)==5)
return true;
else
return false;
}
int main()
{
char str[]="223344AA";
do{
if(check(str))
{
cout<<str;
break;
}
}while(next_permutation(str,str+8));
}