康托展开和逆康托
2017-03-27 21:05
239 查看
彻底搞懂康托和逆康托
康拓展开
康托展开表示的是当前排列在n个不同元素的全排列中的名次
ans = an*(n-1)! + an-1 * (n-2)! + …+ a2 * 1! + a1 * 0!
其中表示第i个元素在未出现的元素中排列第几。
举个简单的例子:
对于排列4213来说,
(1)4在4213中排第3,注意从0开始,
(2)2在213中排第1,
(3)1在13中排第0,
(4)3在3中排第0,即:
这样得到4213在所有排列中排第ans=20(除第一个以外,比如1234这个排列,第20个是4132,第21个才是4213)
还有就是逆康托:
例 {1,2,3,4,5}的全排列,并且已经从小到大排序完毕
找出第96个数
(1)首先用96-1得到95
(2)用95去除4! 得到3余23
(3)用23去除3! 得到3余5
(4)用5去除2!得到2余1
(5)用1去除1!得到1余0
计算:
(1)有3个数比它小的数是4,所以第一位是4
(2)有3个数比它小的数是4但4已经在之前出现过了,所以是5(因为4在之前出现过了所以实际比5小的数是3个)
(3)有2个数比它小的数,是3
(4)有1个数比它小的数,是2
(5)最后一个数只能是1
所以这个数是45321
那如果一个原始数是字符串,或者大整数呢,
下面考虑了long long 范围内也就是字符串18内及以内的数的排列查找第几个数。
比如传入m = 1234, n = 16,那这个结果就是3241,
比如传入字符串m =“abcdefghijklmnopq”, n = 22952601027517,
那这个结果就是”bckfqlajhemgiodnp”,也就是它的第22952601027517排列数是”bckfqlajhemgiodnp”。
康拓展开
康托展开表示的是当前排列在n个不同元素的全排列中的名次
ans = an*(n-1)! + an-1 * (n-2)! + …+ a2 * 1! + a1 * 0!
其中表示第i个元素在未出现的元素中排列第几。
举个简单的例子:
对于排列4213来说,
(1)4在4213中排第3,注意从0开始,
(2)2在213中排第1,
(3)1在13中排第0,
(4)3在3中排第0,即:
这样得到4213在所有排列中排第ans=20(除第一个以外,比如1234这个排列,第20个是4132,第21个才是4213)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll maxn = 18; ll f[maxn]; void init() { ll sum = 1; for (ll i = 1; i <= 18; i++) { sum *= i; f[i] = sum; } } ll Work(string str) { int len = str.length(); ll ans = 0; for (int i = 0; i < len; i++) { int tmp = 0; for (int j = i+1; j < len; j++) { if (str[j] < str[i]) tmp++; } ans += tmp*f[len-i-1]; } return ans; } int main() { init(); string s = "bckfqlajhemgiodnp"; cout << Work(s) << endl; return 0; } //22952601027516
还有就是逆康托:
例 {1,2,3,4,5}的全排列,并且已经从小到大排序完毕
找出第96个数
(1)首先用96-1得到95
(2)用95去除4! 得到3余23
(3)用23去除3! 得到3余5
(4)用5去除2!得到2余1
(5)用1去除1!得到1余0
计算:
(1)有3个数比它小的数是4,所以第一位是4
(2)有3个数比它小的数是4但4已经在之前出现过了,所以是5(因为4在之前出现过了所以实际比5小的数是3个)
(3)有2个数比它小的数,是3
(4)有1个数比它小的数,是2
(5)最后一个数只能是1
所以这个数是45321
那如果一个原始数是字符串,或者大整数呢,
下面考虑了long long 范围内也就是字符串18内及以内的数的排列查找第几个数。
比如传入m = 1234, n = 16,那这个结果就是3241,
比如传入字符串m =“abcdefghijklmnopq”, n = 22952601027517,
那这个结果就是”bckfqlajhemgiodnp”,也就是它的第22952601027517排列数是”bckfqlajhemgiodnp”。
#include <bits/stdc++.h> using namespace std; typedef long long ll; // 12345 ll f[6]; void init(string m) { ll sum = 1; for (ll i = 1; i <= m.length(); i++) { sum *= i; f[i] = sum; } } void Work(string m, ll n) { n--; vector<char> v; vector<char> result; for (ll i = 0; i < m.length(); i++) v.push_back(m[i]); //注意下标vector的下标是从0开始的 for (ll i = m.length()-1; i >= 1; i--) { ll r = n % f[i]; ll s = n / f[i]; n = r; //sort(v.begin(), v.end()); result.push_back(v[s]); v.erase(v.begin()+s); } //最后一个 result.push_back(v[0]); for (ll i = 0; i < m.length(); i++) { cout << result[i]; } cout << endl; } int main() { string m; ll n;//第 n 个 cin >> m; cin >> n; init(m); Work(m, n); return 0; }
相关文章推荐
- 康托展开与逆康托展开
- 康托展开和逆康托展开
- 康托展开和逆康托展开
- 康托展开与逆康托展开
- 康托展开与逆康托展开(bzoj 3301: [USACO2011 Feb] Cow Line)
- 康托展开和逆康托展开的实现
- 康托展开和逆康托展开
- 康托展开和逆康托展开 - Ruby
- 康托展开和逆康托展开
- 康托展开和逆康托展开
- 康托展开(ny139)和逆康托展开
- HDU 1043 Eight POJ 1077 Eight (广度搜索,八数码问题,康托展开)
- hdu1043Eight (经典的八数码)(康托展开+BFS)
- 康托展开及其逆运算--我是第几个,第几是谁
- n个不重复的字符全排列问题 康托展开小结
- ACM-康托展开+预处理BFS之魔板——hdu1430
- HDU 1043 Eight (A* + HASH + 康托展开)
- 【日常学习】【数学/哈希】康托展开
- 康托展开
- 康托展开