康托展開和康托逆展開解決第K個排列問題

2021-07-22 08:56:02 字數 1702 閱讀 7174

集合包含了 n!種不同的排列,將這n!種排列從小到大進行排序,某個排列為第k 個, 求k時,使用康托展開,已知k求對應的排列時,使用康托逆展開。

對於某個排列 a1, a2, a3, .. , an ,將其存入陣列s 求它在n!個排列中的位置k,

用rli表示ai後面比ai小的數的個數,ri表示ai後面的數的個數,

k -1= rl1*r1! + rl2*r2!+…+rln*rn!(rln和rn均為0,可以不用加上)

即 k-1 = rl1*(n-1)! + rl2*(n-2)!+…+rln*0!

**描述:

public

static

intconsmulti(int n)

return res;

}public

static

intkangtuo(int a)

res += temp*consmulti( a.length - i - 1);

}return res + 1;

}

已知排列在第k個位置,求出該排列a1,a2,…,an,相當於對剛才的過程逆向求解。

新建陣列s[n],依次求出a1,a2,…an放入s[n]中存放。

由於 k-1 = rl1*(n-1)! + rl2*(n-2)!+… +rln*0!

令k = k-1,則 k = rl1*(n-1)! + rl2*(n-2)!+… +rln*0!

此時,k已知,n已知,

rl1 = k / (n-1)!

rl1代表a1後面比a1小的數的個數,此時s[0] = a1 = rl1+1;

k = k % (n-1)!

rl2 = k / (n-2)!

rl2代表a2後面比a2小的數的個數,但是此時a2前面也可能存在比a2小的數ll2,a2 = ll2 + rl2 + 1,

0 <= ll2 <=l2(l2表示a2 左邊的數的個數), 從ll2 = 0開始假設,ll2 = 0時,此時a2 = 0 + rl2 + 1,(1)遍歷 a2 左邊數字x,如果存在x == a2, 或者小於a2的數字個數c != ll2, 則此假設不成立,ll2 ++,回歸(1),找到正確 a2 後存入s[1];

……….

依次求得rli 並找到ai存入s[i-1];

……….

由於rln = 0, 最後直接將 中未出現的數字存入s[n-1];

**如下:

public

static

int kthpermu(int n, int k) else else

if (res[h] == j)

}if (equal)

continue;

int tempj = (leftnum + num) + 1;

if (tempj == j) }}

k %= consmulti(n - 1 - i);

}int last = -1;

for (int i = 1; i <= n; i++)

}if (!flag)

}res[n - 1] = last;

return res;

}

康托展開 康托逆展開

x a n n 1 a n 1 n 2 a i i 1 a 1 0 其中a i 為當前未出現的元素中是排在第幾個 從0開始 這就是康托展開。康托展開可用 實現。編輯 把乙個整數x展開成如下形式 x a n n 1 a n 1 n 2 a i i 1 a 2 1 a 1 0 其中a i 為當前未出現的...

康托展開 逆康托展開

康托展開 問題 給定的全排列,計算出它是第幾個排列 求序列號 方法 康托展開 對於乙個長度為 n 的排列 num 1 n 其序列號 x 為 x a 1 n i a 2 n 2 a i n i a n 1 1 a n 0 其中a i 表示在num i 1 n 中比num i 小的數的數量 includ...

康托展開 逆康托展開

用途 康托展開是一種雙射,用於排列和整數之間的對映,可用於排列的雜湊 康托展開 公式 i n1pi i 1 sum limits p i i 1 i n 1 pi i 1 其中p ip i pi 為第i ii個數構成的逆序的個數,n為排列數的個數 例 排列 2134 i n1pi i 1 sum l...