《趣題學演算法》 第1章1 5節置換與輪換

2021-09-23 16:21:21 字數 4400 閱讀 8668

1.5 置換與輪換

設有n個兩兩不等的元素a1, a2, …, an構成的集合a,考慮a到自身的乙個1-1變換σ:a'1=σ(a1), a'2=σ(a2),…,a'n=σ(an)。換句話說,a'1,a'2,…,a'n是a1, a2, …, an的乙個重排。數學中,稱這樣的對應關係σ為a的乙個置換。

【例1】集合a=,σ(2)=1,σ(4)=2,σ(3)=3,σ(1)=4就是a上的乙個置換。

設σ為a=的乙個置換: a2=σ(a1), a3=σ(a2),…,an=σ(an−1),則稱σ為a上的乙個輪換。

【例2】例1中,由於σ(2)=1,σ(1)=4,σ(4)=2,故σ可視為a的子集合a1=上的乙個輪換σ1。

【例3】單元素集合a=上的恒等變換σ(a)=a視為輪換。

置換與輪換之間有如下的重要命題。

定理1-2

集合a=上的任何乙個置換σ,均可唯一[5]地分解成a的若干個兩兩不相交的子集上的輪換,且這些子集的並即為a。

【例4】例1中a=上的置換σ可以分解成例2中a1上的σ1:2→1,1→4,4→2和a2=上的恒等變換σ2:3→3,且a= a1∪a2,a1∩a2=ø。

定理1-2的證明如下。

對集合a所含的元素個數n做數學歸納。當n=1時,a上的任何變換就是恒等變換,所以本身就是乙個輪換。對n>1,假定對元素個數k

問題描述

農夫john有n(1 leqslant nleqslant 10 000)頭牛妞,晚上她們要排成一排**。每個牛妞擁有唯一的乙個值介於1~100000的表示其暴脾氣程度的指標。由於暴脾氣的牛妞更容易損壞john的**裝置,所以john想把牛妞們按暴脾氣指數的公升序(從小到大)重排牛妞們。在此過程中,兩個牛妞(不必相鄰)的位置可能被交換,交換兩頭暴脾氣指數為x、y的牛妞的位置要花費x+y個時間單位。

請你幫助john計算出重排牛妞所需的最短時間。

輸入輸入檔案中包含若干個測試案例資料。每個測試案例由兩行資料組成:

第1行是乙個表示牛妞個數的整數n。

第2行含n個用空格隔開的整數,表示每個牛妞的暴脾氣指數。

n=0是輸入資料結束的標誌。對此案例無需做任何處理。

輸出對每乙個測試案例輸出一行包含乙個表示按暴脾氣指數公升序重排牛妞所需的最少時間的整數。

輸入樣例

3

2 3 1

64 3 1 5 2 6

0

輸出樣例

7

18

解題思路

(1)資料的輸入與輸出

本問題輸入檔案包含若干個測試案例,每個案例的輸入資料有兩行:第1行含有1個表示牛妞個數的整數n,第2行含有n個表示諸牛妞脾氣指數的整數。n=0為輸入資料結束標誌。可以將案例中牛妞脾氣指數組織成乙個陣列,對此陣列計算按脾氣指數公升序排列重排牛妞的最小代價。將計算所得結果作為1行寫入輸出檔案。

1 開啟輸入檔案inputdata

2 建立輸出檔案outputdata

3 從inputdata中讀取人數n

4 while n≠0

5 do 建立陣列a[1..n]

6 for i←1 to n

7 do 從inputdata中讀取a[i]

8 result←cow-sorting(a)

9 將result作為一行寫入outputdata

10 從inputdata中讀取案例資料n

11 關閉inputdata

12 關閉outpudata

其中,第8行呼叫過程cow-sorting(a)計算將牛妞們按脾氣指數公升序排序所花的最小代價,是解決乙個案例的關鍵。

(2)處理乙個案例的演算法過程

對於乙個案例,設定計數器count,初始化為0。設n個牛妞的脾氣指數為a1, a2, …, an,按公升序排列為a'1, a'2, …, a'n。這實際上就是集合a=上的乙個置換σ。按定理1-2知,該置換可表示為a的m(1leqslantmleqslantn)個兩兩不相交子集a1,a2,…,am(且xi _^_}=a)上的輪換σ1,σ2,…,σm。利用定理1-2的證明中的構造方法,依次分解出每個子集ai=(1leqslantileqslantm),若ai是單元素集合,則定義在其上的輪換就是恒等變換,不發生任何代價。今設k>0,直接完成輪換即ai1→ai2→…→aik→ai1。每個元素都參加2次交換,故代價為sumnolimits_^__}}}}。設中的最小者為ti,利用該元素做如下的對換:將ti與應該在其位置上元素交換。這樣,除了ti本身,每個元素都按這樣的方式做了一次交換,從而到達了合適的位置,而ti做了k−1次交換,故代價為sumnolimits_^__}}}}+(k-2)_}。這顯然比sumnolimits_^__}}}}優越,但是有一種情況也許比這更好:將a=中的最小值元素amin先與上述中的最小元素ti交換,產生代價amin+ti。然後按上述方式進行操作,產生代價sumnolimits_^__}}}}+(k-1)_}。最後再amin將與ti交換,產生代價amin+ti。將三者相加得到此方式的總代價:sumnolimits_^__}}}}+(k+1)_}+_}。這樣,我們只需選取min^__}}}}+(k-2)_},sumnolimits_^2__}}}}+(k+1)_}+_}}即為完成子集對換的最小代價。按此方法將每個子集對換的最小代價累加到計數器count中,即為案例所求。將演算法思想表達為偽**過程如下。

cow-sorting(a)

1 n←length[a], count←0

2 copy a to b

3 sort(b)

4 amin←b[1]

5 while n>0

6 do j←a中首個非0元素下標

7 ti←∞, sum←a[j]

8 k←1, ai←a[j]

9 a[j]←0, n←n-1

10 while b[j]≠ai

11 do k←k+1

12 sum←sum+b[j]

13 if ti>b[j]

14 then ti←b[j]

15 j←find(a, b[j])

16 a[j]←0, n←n-1

17 if k>1

18 then count←count+sum+min

19 return count

演算法1-12 計算將牛妞們按脾氣指數公升序重排的最小代價的演算法過程

演算法中設定b為陣列a按公升序排序的結果(第2~3行)。a、b元素之間的對應關係是根據對應下標確定的,即a[i] underrightarrow b[i](1leqslantileqslantn)。第5~18行的while迴圈每次重複構造a的乙個輪換子集,並計算完成該子集元素交換的最小代價,累加到計數器count(第1行初始化為0)中。具體地說,第6行取a中未曾訪問過的元素(a中訪問過的元素置為0)下標為j,設新的子集上輪換的首元素ai。第10~15行的while迴圈按條件b[j]≠ai重複,構造乙個輪換子集。一旦該條件為假(b[j]=ai)意味著輪換完成。在構造過程中,第11行子集元素個數k自增1,第12行將新發現的元素新增到和sum(第7行初始化為該子集的首元素ai)中,第13~14行跟蹤該子集的最小元素ti(第7行初始化為∞)。第15行找出下乙個對應元素下標j,第16行將已經完成訪問的a[j]置為0,且將尚未訪問過的元素個數n(第1行初始化為a的元素個數)自減1。一旦完成乙個輪換子集的構造(第10~16行的while迴圈結束),第17~18行根據子集元素個數k是否大於1,按此前討論的公式決定count的增加值。

演算法的執行時間取決於第11~16行操作被重複的次數。由於每次重複a中的乙個元素值被值為0,而外層迴圈條件為a中非0元素個數n>0,所以第11~16行的操作一定被重複a的元素個數次n(即牛妞的個數)。在11~16行的各條操作中,第15行呼叫find過程在a中查詢值為b[j]的元素下標,這將花費o(n)時間,所以整個演算法的執行時間是o(n2)。

解決本問題的演算法的c++實現**儲存於資料夾laboratory/cow sorting中,讀者可開啟檔案cowsorting.cpp研讀,並試執行之。c++**的解析請閱讀第9章9.4.2節中程式9-53的說明。

計數問題是最基本、最常見的計算問題。本章通過解決10個計算問題討論了解決計數問題的幾個常用的演算法設計方法,包括累積法(問題1-1、問題1-2、問題1-3和問題1-4)、數學計算法(問題1-5、問題1-6和問題1-7)、加法原理和乘法原理(問題1-8)、圖的性質(問題1-9)和置換與輪換(問題1-10)。

[1] 見本書0.5節。

[2] 見本書0.6節。

[3] 參閱本書第7章節7.3。

[4][5] 此處的唯一性指的是將輪換作為元素構成的集合是唯一的。

《趣題學演算法》 第1章1 3節加法原理和乘法原理

1.3 加法原理和乘法原理 組合數學中有兩條著名的原理 加法原理和乘法原理。利用這兩條原理可以快速地解決一些計數問題。加法原理 做一件事,完成它可以有n類辦法,在第一類辦法中有m1種不同的方法,在第二類辦法中有m2種不同的方法,在第n類辦法中有mn種不同的方法,那麼完成這件事共有n m1 m2 m3...

《趣題學演算法》 第0章0 4節演算法的正確性

0.4 演算法的正確性 解決乙個計算問題的演算法是正確的,指的是對問題中任意合法的輸入均應得到對應的正確輸出。大多數情況下,問題的合法輸入無法窮盡,當然就無法窮盡輸出是否正確的驗證。即使合法輸入是有限的,窮盡所有輸出正確的驗證,在實踐中也許是得不償失的。但是,無論如何,我們需要保證設計出來的演算法的...

《設計團隊協作權威指南》 第1章1 5節總結

1.5 總結 在充分展開有關合作和衝突的問題之前,我首先引出了關於設計團隊的一些概念和認識。在乙個專案和團隊背後有4個關鍵的方面 角色和職責 目標和重點 技術和方法,以及專案引數。上述每個方面背後都包含著一些決定專案成敗的原則。然而,專案的成敗還取決於凝聚團隊的3個因素 謙虛 尊重和包容。儘管這些因...