排列的分解

2021-08-31 15:01:57 字數 1139 閱讀 3195

離散數學裡面大家都學過群,群裡面有種很基本並且很重要的叫做置換群,置換群的元素本質上就是乙個排列(英文 permutation group, 直譯過來應該是排列群)。大家應該都學過當初要把 (4 1 5 2 3) 分解成 (1 4 2)(3 5),這個叫做群的 k-cycle 分解,也就是說,乙個排列(置換群的乙個元素)可以分解成多個 k-cycle。所以,現在問題就是:給定乙個[1, n] 構成的排列,求這個排列的 k-cycle 分解,即輸出每個 k-cycle,允許使用 o(n) 的額外空間。這實際上是乙個迴圈鍊錶問題:

// 為了更貼近前文所述,a 的長度是 n+1,a[0] 未用,a[1..n] 是由 [1, n] 構成的排列 void k_cycle_decomp(const int* a, int n) while (j != i); printf("\n"); } }

由此,可以衍生出另乙個問題:給定兩個包含 n 個元素的平行陣列 p, d, p 是下標陣列,d 是值(資料)陣列,p[i] 是指向 d 的下標,現在 d 已經按 p 有序了,也就是說(現在陣列下標是從 0 到 n-1 ):

對於任意的 i ∈[0, n-1) ,d[p[i]] ≤ d[p[i+1]],現在要求,根據 p 將 d 原地整理成有序陣列,在這個過程中,允許改變 p,不允許使用額外o(n) 空間。有了前面的 k-cycle 分解,這個問題就相當容易了:

void rearrange(int* p, data* d, int n) while (k != i); d[j] = tmp; p[j] = j; } }

條件判斷:

if (i != p[i])實際上同時還是個優化手段,如果本來就 p[i] == i,就不需要任何移動,一旦移動過後,置 p[i] = i 的作用是打標記。

如果把排列的 k-cycle 看成乙個迴圈鍊錶,內迴圈實際上是將鍊錶元素迴圈左移乙個單位。內迴圈使用 do {} while 是因為我們已經知道這個內迴圈至少執行一次,do {} while 在迴圈次數較少時比 while {} 要快不少,具體原因請參考相關資料(組合語言或編譯原理或觀察編譯器生成的彙編碼)。

與這相同的演算法,可以對排列(置換群的元素)進行原地求逆(需要標記,可以將 int 最高位用來做標記),求逆如果不要求原地,那麼就是簡單地讓 output[p[i]] = i ,最後返回 output 即可,原地求逆的具體**我這裡就不寫了。

矩陣分解 Cholesky分解

矩陣分解是將矩陣拆解為數個矩陣的乘積,可分為三角分解 滿秩分解 qr分解 jordan分解和svd 奇異值 分解等。cholesky分解法是求解對稱正定線性方程組最常用的方法之一。可採用如下命令 r chol a 產生乙個上三角陣r,使r r a。若a為非對稱正定,則輸出乙個出錯資訊。r,p cho...

CP分解和Tucker分解的區別

cp分解圖示 tucker分解圖示 兩者的區別如下 1.主要區別 核張量 core tensor tucker分解的結果會形成乙個核張量,即pca中的主成分因子,來表示原張量的主要性質,而cp分解沒有核張量。2.tensor分解是n 秩與低秩近似,而cp分解是秩與低秩近似 在cp分解時我們都是先固定...

矩陣的分解

matlab中有這個恒等式 a triu a,1 tril a,1 diag diag a 將矩陣分解為乙個上三角陣 下三角陣和乙個對角陣。測試如下 format compact a 1 2 3 4 5 6 7 8 9 a 1 2 3 4 5 6 7 8 9 u triu a,1 u 0 2 3 0...