全排列的算法(八)——序数法
全排列的生成算法(八)——序数法
n个元素的全排列有n!个,如果将排列按顺序编号,并能够按照某种方法建立起每一个序号与一个排列之间的对应关系,那么就可以根据序号确定排列,反过来也可以根据排列确定它的序号。根据排列的序号生成对应排列的方法就称为序数法。
通常,我们使用的计数法是十进制数。十进制数的位权是10,也就是逢十进一。另外还有二进制、八进制和十六进制等,它们的位权分别是2、8和16。
排列数与n!的阶乘密切相关,因此可以用一种阶乘进制数来建立排列与它的序号的对应关系。阶乘进制数用0!、1!、2!、……分别作为(从右向左的)第一位、第二位、……的位权,显然这是一种可变的位权。举例来说,一个多位数123,如果是十进制,它的大小是3×100+2×101+1×102=(123)10,就是一百二十三。如果是八进制,就是(123)8=3×80+2×81+1×82=(83)10,就是十进制的83。如果是阶乘进制,它就是3×0!+2×1!+1×2!=(8)10,即十进制的8。
某一个n阶排列的序号是m,那么将m转换为阶乘进制数后,阶乘进制数的第i位就是在i右面比i小的元素个数。例如4阶排列中(从0开始计数的)第19个排列的序号是19,将19转换成阶乘进制数是3010,那么,第一位是0,表明1的右面没有比1小的元素,而第二位是1,则2的右面有一个元素小于2,第三位是0,即3的右面没有比它小的元素,第四位是3,4的右面有3个元素小于它。显然,这个排列是4 2 1 3。
序数法生成全排列的算法如下:
第一步:将排列的序号m转换成阶乘进制数
第二步:根据阶乘进制数的各位数值将元素1、2、……、n赋给数组p的相应元素。
在第一步中,从十进制数转换成阶乘进制数,步骤与一般十进制装换成其他进制数相同,也就是用欲转换的数制的位权除十进制数取余数。
第二步中则与递增进位法相同,将数字n、n-1、……、1填入n个空格的相应位置。
具体算法如下:
//全排列的序数法
//输入:排列元素个数n
//输出:全体排列
#include <iostream>
#include <iomanip>
using namespace std;
Void perm(int);
Void output(int *,int);
int total;
int main(void)
{
freopen("in.dat","r",stdin);
int n;
while(cin>>n)
{
total=0;
perm(n);
}
return 0;
}
void output(int *p,int n)
{
cout<<setw(4)<<++total<<": ";
for(int i=0;i<n;i++)
cout<<setw(3)<<p[i];
cout<<endl;
}
void perm(int n)
{
int i,j,k,m,s;
int *p=new int[n],*q=new int[n];
fill_n(q,n,0); //初始化
m=0; //原始排列序号
while(1)
{
fill_n(p,n,0); //数组初始化
for(i=0;i<n;i++) //按阶乘进制数各位的值安排各元素位置
for(j=n-1,k=0;j>=0;j--) //从n开始
{
if(p[j])
continue;
if(k==q[i])
{
p[j]=n-i;
break;
}
k++;
}
output(p,n); //输出一个排列
s=++m; //下一个排列的序号
for(i=1;i<=n;i++) //将序号转换成阶乘进制数
{
q[n-i]=s%i;
s/=i;
}
for(j=0,k=0;j<n;j++) //如果阶乘进制数各位回到0
k+=q[j];
if(k==0) //结束
break;
}
}
阶乘的序数转换成阶乘进制数后,也可以按照的增进位方式产生后继(阶乘进制)序数。
现在设置数组q,并用q[i]表示阶乘进制数的第n-i-1位,那么就有0≤q[i]≤i-1。这样,从q[0]=q[1]=……出发,对q[n-2]累加1,并按照q[i-1]=i时进位,就可以数次得到序数0、1、……、n!。同时也可以生成全体n阶排列。
//递增进位序数法
//输入:排列元素个数
//输出:全体n阶全排列
#include <iostream>
#include <iomanip>
using namespace std;
void perm(int);
void output(int *,int);
int total;
int main(void)
{
freopen("in.dat","r",stdin);
int n;
while(cin>>n)
{
total=0;
perm(n);
}
return 0;
}
void output(int *p,int n)
{
cout<<setw(5)<<++total<<": ";
for(int i=0;i<n;i++)
cout<<setw(3)<<p[i];
cout<<endl;
}
void perm(int n)
{
int *p=new int[n];
int *q=new int[n]; //阶乘进制数
fill_n(q,n,0); //初始化
int i,j,k;
while(1)
{
fill_n(p,n,0); //初始化
for(i=0;i<n;i++) //按照阶乘进制数各位安排元素位置
for(j=n-1,k=0;j>=0;j--)
{
if(p[j])
continue;
if(k==q[i])
{
p[j]=n-i;
break;
}
k++;
}
output(p,n); //输出一个排列
i=n-2; //计算下一个序数
q[i]++;
while(q[i]>n-i-1 && i>0) //递增进位
q[i--]=0,q[i]++;
if(q[0]==n) //超出n位
break; //结束
}
}
int main(void)
{
int n=5;
total=0;
perm(n);
return 0;
}
全排列的算法(八)——序数法相关推荐
- c支限界算法语言n皇后问题分,算法(八)-回溯法-N皇后问题
问题描述: 算法思想: 代码实现: #include using namespace std; class Queen { friend int nQueen(int);//求解八皇后 private ...
- c语言全排列库函数,几种全排列的算法(C语言实现)
/* * 几种排列组合的算法 */ #include int a[20]; int n; //打印数组 void showArray(int *a) { int i; for(i=1;i<=n; ...
- 排列的生成(二) —— 序数法
1. 定义 n n n个元素的全排列有 n ! n! n!个,如果将排列按顺序编号,并能够按照某种方法建立起每一个序号与一个排列之间的对应关系,那么就可以根据序号确定排列,反过来也可以根据排列确定它的 ...
- 五大经典算法之回溯法
一.基本概念 回溯法,又称为试探法,按选优条件向前不断搜索,以达到目标.但是当探索到某一步时,如果发现原先选择并不优或达不到目标,就会退回一步重新选择,这种达不到目的就退回再走的算法称为回溯法. ...
- 分油问题回朔法c语言算法,用回溯法求“韩信分油”问题所有解
裴南平 摘要:回溯法是一种常用的计算机程序设计方法.使用回溯法解决"韩信分油问题"也称"泊松分酒问题",在算法中保存每一步执行的中间结果,程序扩展前,判斷程序是 ...
- 第39级台阶回溯算法c语言,五大经典算法之回溯法 - osc_9ipdey7e的个人空间 - OSCHINA - 中文开源技术交流社区...
一.基本概念 回溯法,又称为试探法,按选优条件向前不断搜索,以达到目标.但是当探索到某一步时,如果发现原先选择并不优或达不到目标,就会退回一步重新选择,这种达不到目的就退回再走的算法称为回溯法. 与穷 ...
- 求全排序的经典算法“后补法”
//用于求全排序的经典算法"后补法",代码如下: #include <stdio.h> #include <conio.h> #include <st ...
- 算法最少分组法_数据结构
20210328 https://blog.csdn.net/sinat_41144773/article/details/89530403 树.二叉树(完全二叉树.满二叉树)概念图解 二叉树:每个结 ...
- java 二分查找_计算机入门必备算法——二分查找法
1.引言 笔者对于计算机的研究一直停滞不前,近期想对一些算法进行复习和进一步的研究,每天都会更新一个新的算法,算法有难有易,层层递进.不希望能学的有多么高深,只希望在一些最基本的算法上有编码的思路,或 ...
最新文章
- Python入门100题 | 第050题
- tensorflow在训练的时候权重是nan,如何解决
- 1.3.3 错题整理(组成原理)
- eclipse export jar file 和 runnable jar file 的区别
- Java执行存储过程
- 【qduoj - 1012】反转数字(模拟,水题)
- bat导出远程oracle数据,windows 任务计划 实现oracle远程 数据库备份
- cli php 增强包_Linux 上安装 PHP 扩展
- 数据结构与算法(三)-线性表之静态链表
- linux 解压加密zip,linux 系统下 zip 的加密压缩与解压缩命令
- 《刘润·5分钟商学院》学习总结01
- 小米商城网页制作大全-完结篇
- PHP学习之SAPI
- numpy到pytorch,鸟枪换炮
- 8个免费的高质量UI图标大全网站
- Arduino使用雨滴模块
- 更新again:微机原理与汇编语言-练习题
- 画论56 恽格《南田画跋》
- Windows-tree命令生成目录树
- 图像增强算法汇总(直方图均衡化、拉普拉斯、Log变换、gamma伽马变换)附MATLAB代码