NYIST 139 我排第幾個(康託展開)

關於康拓展開:

康託展開是一個全排列到一個自然數雙射,常用於構建哈希表時的空間壓縮。 康託展開的實質是計算當前排列在所有由小到大全排列中的順序,因此是可逆的。

以下稱第x個全排列是都是指由小到大的順序。

公式

X = a[n]*(n-1)! + a[n-1]*(n-2)! + ... + a[i]*(i-1)! + ... + a[1]*0!

其中,a[i]爲整數,並且0 <= a[i] < i, 1 <= i <= n。

a[i]的意義參見舉例中的解釋部分

舉例

例如,3 5 7 4 1 2 9 6 8 展開爲 98884。因爲X = 2*8! + 3*7! + 4*6! + 2*5! + 0*4! + 0*3! + 2*2! + 0*1! + 0*0! = 98884.

解釋:

排列的第一位是3,比3小的數有兩個,以這樣的數開始的排列有8!個,因此第一項爲2*8!

排列的第二位是5,比5小的數有1、2、3、4,由於3已經出現,因此共有3個比5小的數,這樣的排列有7!個,因此第二項爲3*7!

以此類推,直至0*0!

因此,3 5 7 4 1 2 9 6 8是第98884小的排列。


維基百科上的介紹:http://zh.wikipedia.org/zh/%E5%BA%B7%E6%89%98%E5%B1%95%E5%BC%80

題目鏈接:http://acm.nyist.net/JudgeOnline/problem.php?pid=139


本題代碼如下:

#include <cstdio>

const int f[13] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600};

int kt(char s[],int n) //n表示該排列有n個數
{
    int sum = 0;
    for(int i = 0; i < n; i++)
    {
        int temp = 0;
        for(int j = i + 1; j < n; j++)
            if(s[j] < s[i])
                temp ++;
        sum += f[n - 1 - i] * temp; //f[n]表示n的階乘
    }
    return sum + 1;
}

int main()
{
    int n;
    char s[13];
    scanf("%d", &n);
    while(n--) {
        scanf("%s", s);
        printf("%d\n", kt(s, 12));
    }
    return 0;
}



發佈了40 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章