康託展開

概述

康託展開是一個全排列到一個天然數的雙射。設有n個數(1,2,3,4,…,n),能夠有組成不一樣(n!種)的排列組合,康託展開表示的就是是當前排列組合在n個不一樣元素的全排列中的名次。c++

康託展開

公式

\(X = a[n] * (n - 1)! + a[n - 1] * (n - 2)! + a[n - 2] * (n - 3)! …… + a[2] * 1! + a[1] * 0!\)app

例子

例如3的全排列優化

  • 123 \(0 * 2! + 0 * 1! + 0 * 0! = 0\)
  • 132 \(0 * 2! + 1 * 1! + 0 * 0! = 1\)
  • 213 \(1 * 2! + 0 * 1! + 0 * 0! = 2\)
  • 231 \(1 * 2! + 1 * 1! + 0 * 0! = 3\)
  • 312 \(2 * 2! + 0 * 0! + 0 * 0! = 4\)
  • 321 \(2 * 2! + 1 * 1! + 0 * 0! = 5\)

樣例解釋

估計你們應該不用解釋都應該明白了,這裏的a[i]係數是如何來的了spa

  • 321 \(2 * 2! + 1 * 1! + 0 * 0!\)

3 > 2, 3 > 1,獲得a[3] = 2,2 > 1,獲得a[2] = 1
其中的康託展開的數值表明的是當前項在全排類中的數值下標(注意下標從0開始計數)code

康託展開代碼

/*
	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

逆康託展開

也就是康託展開的逆過程,就拿上面的例子來講it

排列4 5 3 1 2的康託展開值是94。class

逆運算計算過程

  • 94 / 4! = 3 餘 22,從(1 2 3 4 5)中獲得第四大的爲當前位的數字(4)
  • 22 / 3! = 3 餘 4,從(1 2 3 5) 中獲得第四大的爲當前位的數字(5)
  • 4 / 2! = 2 餘 0,從(1, 2, 3) 中獲得第三大的爲當前位的數字(3)
  • 0 / 1!= 0 餘 0,從(1, 2) 中獲得第二大的爲當前位的數字(1)
  • 直到剩下最後一位

逆運算代碼

/*
	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;
}
相關文章
相關標籤/搜索