铁路超高发展概况:官方简介:
康托展开是完全按自然数排列的双射,常用于构建散列表时的空间压缩。 铁路超展开的本质是计算当前从小到大所有数组中的顺序,其是可逆的。
通俗简介:
在纸箱展开中,例如,可以求出数组的编号,在该数组中,12345的号码为1,12345的号码为2,按照字典顺序将号码增加,依次类推。
康托反展开可以解开一个号码,与之对应的排列是什么?
铁路超高展开解释:给出铁路超高展开的公式:
首先说明这个公式中的变量。 大家不理解这个公式也没关系。 慢慢地看后面。 很简单。
的意思是,从右向左第I个位数是这个数之前没有出现的数,是最大的。 举例来说,你可以看到这个公式:
注意:在计算时,12345序列应视为第0序列,其理由将在后面叙述。
以52413为例:
1、首先请看第一位的数5。 不管第一位是什么数,后面都有四位。 那么,这4位的全部排列方法是4。 因为种类比第一位是1、2、3、4或5开始的词典顺序小,所以如果把1、2、3、4分别作为开头的话就是4 * 4! 排列法比52413这样的排列法的词典顺序小。
那么,最初的数是1、2、3、4时的词典顺序的数完是4 * 4! 种,而且这些字典的顺序都小于52413的字典的顺序。
还有其他比52413的词典顺序小的排列吗?
2、那么可以固定第一位的5,找下一位的2。 此时,因为5已经用过了,所以从剩下的1、2、3、4中选出小于2的数,一共一个,后面剩下的三个,也就是3! 考虑到排列方式,这个时候比52413字典小的还有1 * 3! 种子,也就是5是第一位,1是第二位的时候。
看看第三个4。 此时,5、2都使用了,所以从剩下的1、3、4的3个数中寻找小于4的数,与有2个小于4的数的原理相同,所以此时也可以有2 * 2。 种排列方式的词典顺序小于52413
看看第四名第一名。 这时,有0 * 1! 种
看五、五位三,这个时候有0 * 0! 种
综上所述:
序列: 52413展开这个序列,就是4 * 4! 1 * 3! 2 * 2! 0 * 1! 0 * 0! 的计算结果是106
因为是从0开始计数,所以最后52413的号码是107
为什么要从0开始计数?
可以这样看。 现在,让我求出12345的纸箱展开值。 也就是说0*4。 0*3! 0*2! 0*1! 0*0!=0,所以你明白了吧~
康托表达式的最小词典顺序编号为0。
铁路超高展开代码:/*****此处通过以字符串形式显示字符串来实现高度通用性* * * */# include iostream # include cstdio # include vector # includealgorithmusior voidJie_Cheng(intn ) { f[0]=f[1]=1; //0的阶乘为1for(intI=2; i=n; I ) f(I )=f(I-1 ) *I; () ) )、铁路超高展开(,(,(,(,(,),)、)、()、(,)、()、)、)、()、()、()、()、()、)、(stringstr; int kangtuo () { int ans=1; //注意,12345数为0开始计算,所以最后的结果是12345为最初的int len=str.length (); for(intI=0; i len; I ) { int tmp=0; //用于计数的for(intj=I1; j len; j () if ) str[I]str[j] ) tmp; 计算str[i]是第几个大的数,或者有几个比他小的数(} ans =tmp * f[len - i - 1]; } return ans; }int main () Jie_Cheng ) 10; string str='52413 '; coutkangtuo () endl; (康托反向展开解释)这里直接打开栗子。
如果初始数组是12345(1 (第一个),则系统会提示您输入第107个数组是什么。 (按词典顺序递增)
这样计算:
请先从107减去1。 因为铁路超高展开的初始序列号是0
然后计算后缀积。
1 2 3 4 5
5! 4! 3! 2! 1! 0!
120 24 6 2 1 1
106 / 4! = 4 ······ 10 有4个比它小的所以因该是5 从(1,2,3,4,5)里选
10 / 3! = 1 ······ 4 有1个比它小的所以因该是2 从(1, 2, 3, 4)里选
4 / 2! = 2 ······ 0 有2个比它小的所以因该是4 从(1, 3, 4)里选
0 / 1! = 0 ······ 0 有0个比它小的所以因该是1 从(1,3)里选
0 / 0! = 0 ······ 0 有0个比它小的所以因该是3 从(3)里选
所以编号107的是 52413
康托逆展开代码: /***** 这里以字符串进行展示 字符串可泛化性好 ******/#include<iostream>#include<cstdio>#include<vector>#include<algorithm>using namespace std;/*******打出1-n的阶乘表*******/int f[20];int x, num;void jie_cheng(int n){ f[0] = f[1] = 1; // 0的阶乘为1 for(int i = 2; i <= n; i++) f[i] = f[i - 1] * i;}/**************康托逆展开**************/vector<char> vec; //存需要排列的字符void rev_kangtuo(int k) //输出序号为 k 的字符序列{ int n = vec.size(), len = 0; string ans = ""; k--; // 算的时候是按 12345 是第0位 for(int i = 1; i <= n; i++){ int t = k / f[n - i]; // 第 i 位需要 第 t + 1 大的数 k %= f[n - i]; //剩下的几位需要提供的排列数 ans += vec[t] ; // vec[t] 就是第 t + 1 大的数 vec.erase(vec.begin() + t); //用过就删了,不用vector用暴力也可以,就是说枚举,然后一个一个的比较大小,并记录有几个没用过的字符且字典序比它小 } cout << ans << 'n';}/***************************************/// 假设展开后不超过10位int main(){ jie_cheng(10); // 预处里好阶乘 scanf("%d", &x); // 输入需要逆展开的数字 /************康托逆展开***********/ for(int i = 1; i <= 10; i++) { if(x / f[i] == 0) // 求出 x 逆展开所需的最小的位数,方便下面的初始化 { num = i; break; } } for(int i = 1; i <= num; i++) vec.push_back(i + '0'); //输入的位数只要不小于num就可以 rev_kangtuo(x);}