康托展开可以用来表示一个数字只出现一次的状态(也就是n的排列),应用于dp或者搜索里面的状态压缩。一个排列对应的数字是这个排列在全排列中的字典序排名
例如: ( 1 , 2 , 3 , 4 ) (1, 2, 3, 4) (1,2,3,4) 可以用 0 0 0 来表示, ( 1 , 2 , 4 , 3 ) (1, 2, 4, 3) (1,2,4,3) 可以用 1 1 1 来表示
康托展开:
int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
int cantor(int s[], int l) { //transfer array s[] to integer, l is length of array s[]
int sum = 0;
for (int i = 0; i < l; ++i) {
int num = 0;
for (int j = i + 1; j < l; ++j)
if (s[j] < s[i]) num++;
sum += (num * fac[l - i - 1]);
}
return sum;
}
康托逆展开:
int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
void inv_cantor(int s[], int n, int l) { //transfer integer n to array s[], l is length of array s[]
bool vis[l];
memset(vis, false, sizeof(vis));
for (int i = 0; i < l; ++i) {
int tmp = n / fac[l - i - 1];
n %= fac[l - i - 1];
for (int j = 0, pos = 0; ; ++j, ++pos) {
if (vis[pos]) --j;
if (j == tmp) {
vis[pos] = true;
s[i] = pos + 1;
break;
}
}
}
}