从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。如果这组数有n个,那么全排列数为n!个。
Ex:a,b,c的全排列一共有3!= 6 种 分别是{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a}。
1.非stl的全排列
先来个代码:以1-9数字的全排列为例:
void permutation(int st,int n){
if(st == n) DO(pmut);//DO为对排列结果的操作
else{
for(int i = 1;i <= 9;i++){//1-9全排列
if(!vis[i]){
pmut[st] = i;
vis[i] = 1;
permutation(st + 1,n);
vis[i] = 0;
}
}
}
}
·pmut记录每一个排列:对于全排列中st,表示排列的结果是从st开始记录一直记录到n,一般取st = 1,vis记录所排列的数据是否被访问过了,则全排列其实就是一个枚举,对pmut数组的每个位置依次放入数据,例如st位置依次放置从1-9的数字,然后知道数组放满(到n位置)结束,则此时pmut就是一种排列。
·DO函数表示对每一个排列的结果的操作,例如输出排列的结果:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 106;
int pmut[maxn];
int vis[maxn];
void DO(int pmut[]){
for(int i = 1;i <= 9;i++)
cout<<" "<<pmut[i];
cout<<endl;
}
void permutation(int st,int n){
if(st == n) DO(pmut);
else{
for(int i = 1;i <= 9;i++){
if(!vis[i]){
pmut[st] = i;
vis[i] = 1;
permutation(st + 1,n);
vis[i] = 0;
}
}
}
}
int main(){
memset(vis,0,sizeof vis);
permutation(1,10);
return 0;
}
2.stl-next_permutation与prev_permutation(bool)函数
1.头文件
#include <algorithm>
2.下一个排列与上一个排列的概念:
我们假设一个数组为1 2 7 5,对此进行升序排列:1 2 5 7,此时定义此数组的升序排列为所有排列的第一个排列结果,则此下一个排序结果为1 2 7 5,1 5 2 7...
也就是说是:对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,它的下一个序列即为{a, c, b},而{a, c, b}的上一个序列即为{a, b, c},同理可以推出所有的六个序列为:{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}没有上一个元素,{c, b, a}没有下一个元素。
1)next_permutation:求下一个排列组合
a.函数模板:next_permutation(arr, arr+size);
b.参数说明:
arr: 数组名
size:数组元素个数
c.函数功能: 返回值为bool类型,当当前序列不存在下一个排列时,函数返回false,否则返回true,排列好的数在数组中存储
d.注意:在使用前需要对欲排列数组按升序排序,否则只能找出该序列之后的全排列数。
比如,如果数组num初始化为2,3,1,那么输出就变为了:{2 3 1} {3 1 2} {3 2 1}
2)prev_permutation:求上一个排列组合
a.函数模板:prev_permutation(arr, arr+size);
b.参数说明:
arr: 数组名
size:数组元素个数
c.函数功能: 返回值为bool类型,当当前序列不存在上一个排列时,函数返回false,否则返回true
d.注意:在使用前需要对欲排列数组按降序排序,否则只能找出该序列之后的全排列数。
对上面那个代码用stl书写一遍(1-9数字的全排列):
#include<bits/stdc++.h>
using namespace std;
const int maxn = 106;
int pmut[maxn];
void DO(int pmut[]){
for(int i = 1;i <= 9;i++)
cout<<" "<<pmut[i];
cout<<endl;
}
int main(){
for(int i = 1;i <= 9;i++)
pmut[i] = i;
do{
DO(pmut);
}while(next_permutation(pmut + 1,pmut + 10));
return 0;
}
3.PREV-3 带分数
问题描述
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
输入格式
从标准输入读入一个正整数N (N<1000*1000)
输出格式
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
样例输入1
100
样例输出1
11
样例输入2
105
样例输出2
6
分析:
将这个题看成这样的形式num = a + b / c,也就是说a,b,c三个数字是1-9数字的一种情况,然后再在其中加入一个+号和一个/号,也就是我们只需要知道所有的排列结果,然后在其中合适的位置插入+和/号即可,为了简化枚举的情况,分析a,b,c的情况:(a)表示a的位数
1.a <= num
2.(c)min = 1
3.a是整数,所有b/c也是整数,即b % c = 0
4.b > c -> (b) >= c,由此可以推出了( 9 - (a) ) / 2 <= (b) <= 8 - (a)
对于全排列的每一个结果pmut,枚举插入+的位置(i),则之前就是a,后面的部分枚举/的位置(j),则i + 1到j的为b,剩下的为c即可
由此就可以直接解出此题(stl与非stl):
1.不使用stl
#include<iostream>
#include<cstring>
using namespace std;
int vis[10];
int pmut[10];
int sum;
int num;
void DO(int pmut[]) {
int a,b,c;//i,j,rest
for(int i = 1;i <= 9;i++) {
a = 0;
for(int k = 1;k <= i;k++){
a = a*10 + pmut[k];
if(a >= num) return ;
}
for(int j = (9 - i)/2 + i;j <= 8;j++) {
b = 0,c = 0;
for(int k = i + 1;k <= j;k++)
b = b*10 + pmut[k];
for(int k = j + 1;k <= 9;k++)
c = c*10 + pmut[k];
if(b % c == 0 && a + b/c == num)
sum++;
}
}
}
void permutation(int st,int n) {
if(st == n) DO(pmut);
else {
for(int i = 1;i <= 9;i++) {
if(!vis[i]) {
pmut[st] = i;
vis[i] = 1;
permutation(st + 1,n);
vis[i] = 0;
}
}
}
}
int main() {
while(cin>>num){
memset(vis,0,sizeof(vis));
sum = 0;
permutation(1,10);
cout<<sum<<endl;
}
return 0;
}
2.stl
#include<bits/stdc++.h>
using namespace std;
const int maxn = 16;
int pmut[maxn];
int sum;
int num;
void DO(int pmut[]) {
int a,b,c;//i,j,rest
for(int i = 1;i <= 9;i++) {
a = 0;
for(int k = 1;k <= i;k++){
a = a*10 + pmut[k];
if(a >= num) return ;
}
for(int j = (9 - i)/2 + i;j <= 8;j++) {
b = 0,c = 0;
for(int k = i + 1;k <= j;k++)
b = b*10 + pmut[k];
for(int k = j + 1;k <= 9;k++)
c = c*10 + pmut[k];
if(b % c == 0 && a + b/c == num)
sum++;
}
}
}
int main(){
for(int i = 1;i <= 9;i++)
pmut[i] = i;
while(cin>>num){
sum = 0;
do{
DO(pmut);
}while(next_permutation(pmut + 1,pmut + 10));
cout<<sum<<endl;
}
return 0;
}