集合包含了 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...