标签:oid += 估计 bit names 注意 clu == void
康托展开是一个全排列到一个自然数的双射。设有n个数(1,2,3,4,…,n),可以有组成不同(n!种)的排列组合,康托展开表示的就是是当前排列组合在n个不同元素的全排列中的名次。
\(X = a[n] * (n - 1)! + a[n - 1] * (n - 2)! + a[n - 2] * (n - 3)! …… + a[2] * 1! + a[1] * 0!\)
例如3的全排列
估计大家应该不用解释都应该明白了,这里的a[i]系数是如何来的了
3 > 2, 3 > 1,得到a[3] = 2,2 > 1,得到a[2] = 1
其中的康托展开的数值代表的是当前项在全排类中的数值下标(注意下标从0开始计数)
/*
Code by lifehappy 2020:04:21
康托展开计算O(n * n)
未优化,明天把优化的代码补上。
*/
#include<bits/stdc++.h>
using namespace std;
int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};//阶乘
int cantor(int a[], int n) {
int s = 0;
for(int i = 0; i < n; i++) {
int num = 0;
for(int j = i + 1; j < n; j++)
if(a[i] > a[j])
num++;
s += num * fac[n - i - 1];
}
return s;
}
int main() {
int a[5] = {4, 5, 3, 1, 2}, n = 5;
printf("%d\n", cantor(a, n));
return 0;
}
94
也就是康托展开的逆过程,就拿上面的例子来说
排列4 5 3 1 2的康托展开值是94。
/*
Code by lifehappy 2020:04:21
逆康托展开计算O(n * n)
康托展开项未优化
*/
#include<bits/stdc++.h>
using namespace std;
int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};//阶乘
int ans[10];
int cantor(int a[], int n) {
int s = 0;
for(int i = 0; i < n; i++) {
int num = 0;
for(int j = i + 1; j < n; j++)
if(a[i] > a[j])
num++;
s += (num * fac[n - i - 1]);
}
return s;
}
void decantor(int s, int n) {
vector<int> a;
for(int i = 1; i <= n; i++) a.push_back(i);
for(int i = 4; i >= 0; i--) {
int pos = s / fac[i];
s %= fac[i];
ans[n - i - 1] = a[pos];
a.erase(a.begin() + pos);
}
}
int main() {
int a[5] = {4, 5, 3, 1, 2}, n = 5;
printf("%d\n", cantor(a, n));
decantor(cantor(a, n), n);
for(int i = 0; i < n; i++)
printf("%d%c", ans[i], i + 1 == n ? ‘\n‘ : ‘ ‘);
return 0;
}
标签:oid += 估计 bit names 注意 clu == void
原文地址:https://www.cnblogs.com/lifehappy/p/12748712.html