全排列打表
全排列打表原理:
递归实现:
假设我们要对1,2,3,4四个数进行全排列,过程如下:
(a)首先保持1不变,对2,3,4全排列;
(b)保持2不变,对3,4全排列;
(c)保持3不变,对4全排列,4的排列只有一种。得到1,2,3,4
(d)然后3不能不变了,继续保持2不变,3,4互换得到1,2,4,3
(e)以1,2打头的排列完成,接下来把3换到2的位置,继续(c)、(d)的操作
...
(a)首先保持1不变,对2,3,4全排列;
(b)保持2不变,对3,4全排列;
(c)保持3不变,对4全排列,4的排列只有一种。得到1,2,3,4
(d)然后3不能不变了,继续保持2不变,3,4互换得到1,2,4,3
(e)以1,2打头的排列完成,接下来把3换到2的位置,继续(c)、(d)的操作
...
code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; /* (1)n个元素的全排列=(n-1个元素的全排列)+(另一个元素作为前缀); (2)出口:如果递归到只有一个元素的全排列,则说明已经排完,则输出数组; (3)不断将每个元素放作第一个元素,然后将这个元素作为前缀,并将其余元素继续全排列,等到出口,出口出去后还需要还原数组; */ const int maxn = 1e5+10; int a[maxn],n; void dfs(int b[],int k){ if(k==n){ for(int i=1;i<=n;i++){ printf("%d ",b[i]); } printf("\n"); return ; } for(int i=k;i<=n;i++){ swap(a[i],a[k]); dfs(a,k+1); swap(a[i],a[k]); } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) a[i] = i; dfs(a,1); return 0; }
关于STL中打印全排列表的使用:
有关全排列函数:next_permutation(iterator start,iterator end),和prev_permutation(iterator start,iterator end);
这两个函数作用是一样的,区别就在于前者求的是当前排列的下一个字典序排列,后一个求的是当前排列的上一个字典序排列 是否存在。
进行自定义全排列 next_permutation(node,node+n,cmp)
next_permutation(num,num+n)函数是对数组num中的前n个元素进行全排列
#include <stdio.h> #include <algorithm> using namespace std; int main(){ int n; while(scanf("%d",&n)&&n){ int a[1000]; for(int i=0;i<n;i++){ scanf("%d",&a[i]); } sort(a,a+n); do{ for(int i=0;i<n;i++) printf("%d ",a[i]); printf("\n"); }while(next_permutation(a,a+n)); } return 0; }
例题:
2017第八届蓝桥杯-c++决赛A组 题目1
题目:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
随意组合 小明被绑架到X星球的巫师W那里。 其时,W正在玩弄两组数据 (2 3 5 8) 和 (1 4 6 7) 他命令小明从一组数据中分别取数与另一组中的数配对,共配成4对(组中的每个数必被用到)。 小明的配法是:{(8,7),(5,6),(3,4),(2,1)} 巫师凝视片刻,突然说这个配法太棒了! 因为: 每个配对中的数字组成两位数,求平方和,无论正倒,居然相等: 87^2 + 56^2 + 34^2 + 21^2 = 12302 78^2 + 65^2 + 43^2 + 12^2 = 12302 小明想了想说:“这有什么奇怪呢,我们地球人都知道,随便配配也可以啊!” {(8,6),(5,4),(3,1),(2,7)} 86^2 + 54^2 + 31^2 + 27^2 = 12002 68^2 + 45^2 + 13^2 + 72^2 = 12002 巫师顿时凌乱了。。。。。 请你计算一下,包括上边给出的两种配法,巫师的两组数据一共有多少种配对方案具有该特征。 配对方案计数时,不考虑配对的出现次序。 就是说: {(8,7),(5,6),(3,4),(2,1)} 与 {(5,6),(8,7),(3,4),(2,1)} 是同一种方案。 注意:需要提交的是一个整数,不要填写任何多余内容(比如,解释说明文字等)
思路:
由于给出的两个序列均只有4个值,所以我们可以全排列枚举匹配所有组成然后判值,如果相等则结果++
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <algorithm> #include <iostream> #include <cstring> using namespace std; int a1[4]={2,3,5,8}; int a2[4]={1,4,6,7}; int ans=0; bool judge() { int b1[4],temp1=0; int b2[4],temp2=0; for(int i=0; i<4; i++) { b1[i]=a1[i]*10+a2[i]; b2[i]=a1[i]+a2[i]*10; temp1+=b1[i]*b1[i]; temp2+=b2[i]*b2[i]; } if(temp1 == temp2) { return true; } } //保证每一个元素不相同则输出全排列总个数为n! void fun(int x) { if(x == 4) { if(judge()) ans++; return; } //递归全排列 for(int i=x; i<4; i++) { swap(a1[i],a1[x]); fun(x+1); //回溯 swap(a1[i],a1[x]); } } int main() { fun(0); cout<<"ans: "<<ans<<endl; return 0; }