1.3 加法原理和乘法原理
組合數學中有兩條著名的原理——加法原理和乘法原理。利用這兩條原理可以快速地解決一些計數問題。
加法原理:做一件事,完成它可以有n類辦法,在第一類辦法中有m1種不同的方法,在第二類辦法中有m2種不同的方法,……,在第n類辦法中有mn種不同的方法,那麼完成這件事共有n=m1+m2+m3+…+mn種不同方法。
乘法原理:做一件事,完成它需要分成n個步驟,做第一步有m1種不同的方法,做第二步有m2種不同的方法,……,做第n步有mn種不同的方法,那麼完成這件事共有n=m1×m2×m3×…×mn種不同的方法。
維基百科
問題描述
氣泡排序是一種簡單的排序演算法。該演算法反覆掃瞄欲排序的列表,比較相鄰元素對,若兩者順序不對,就將它們交換。這樣對列表的掃瞄反覆進行直至列表中不存在需要交換的元素為止,這意味著列表已經排好序。演算法之所以叫此名字,是緣於最小的元素就像「泡泡」一樣冒到列表的頂端,這是一種基於比較的排序演算法。
氣泡排序是一種非常簡單的排序演算法,其執行時間為o(n2)。每趟操作從列表首開始,以此比較相鄰項,需要時交換兩者。重複進行若干趟這樣的操作直至無需再做任何交換操作為止。假定恰好做了t趟操作,序列就按公升序排列,我們就說t為對此序列的氣泡排序趟數。下面是乙個例子。序列為「5 1 4 2 8」,對其施行的氣泡排序如下所示。
第一趟操作:
( 51 4 2 8 ) −> ( 1 5 4 2 8 ),比較頭兩個元素,並將其交換。
( 1 5 4 2 8 ) −> ( 1 4 5 2 8 ),交換,因為5 > 4。
( 1 4 5 2 8 ) −> ( 1 4 2 5 8 ),交換,因為5 > 2。
( 1 4 2 5 8 ) −> ( 1 4 2 5 8 )由於這兩個元素已經保持順序(8>5),演算法不對它們進行交換。
第二趟操作:
( 1 4 2 5 8 ) −> ( 1 4 2 5 8 )
( 1 4 2 5 8 ) −> ( 1 2 4 5 8 ),交換,因為4 > 2。
( 1 2 4 5 8 ) −> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) −> ( 1 2 4 5 8 )
在t = 2趟後,序列已經排好序,所以我們說對此序列氣泡排序的趟數為2。
zx在演算法課中學習氣泡排序,他的老師給他留了乙個作業。老師給了zx乙個具有n個兩兩不等的元素的陣列a,並且已經排成公升序。老師告訴zx,該陣列是經過了k趟的氣泡排序得來的。問題是:a有多少種初始狀態,使得對其進行氣泡排序,趟數恰為k?結果可能是乙個很大的數值,你只需輸出該數相對於模20100713的剩餘。
輸入輸入包含若干個測試案例。
第一行含有乙個表示案例數的整數t (tleqslant100 000)。
跟著的是t行表示各案例的資料。每行包含兩個整數n和k(1leqslantnleqslant1,000,000, 0leqslantkleqslantn−1),其中n表示序列長度而k表示對序列進行氣泡排序的趟數。
輸出對每個案例,輸出序列的初始情形數對模20100713的剩餘,每個一行。
輸入樣例
3
3 03 1
3 2
輸出樣例
1
32
解題思路
(1)資料的輸入與輸出
根據輸入檔案格式的描述,首先在其中讀出測試案例個數t。然後依次讀取案例資料n和k。對每個案例計算進行k趟處理就能實現氣泡排序的陣列a[1..n]有多少種可能的初始狀態,並將所得結果作為一行寫入輸出檔案。
1 開啟輸入檔案inputdata
2 建立輸出檔案outputdata
3 從inputdata中讀取案例數t
4 for t←1 to t
5 do 從inputdata中讀取案例資料n, k
6 bublle-sort-rounds(n, k, k, x, count)
7 將count作為一行寫入outputdata中
8 關閉inputdata
9 關閉outpudata
其中,第6行呼叫過程bublle-sort-rounds(n, k, k, x, count)計算進行k趟處理就能實現氣泡排序的陣列a[1..n]有多少種可能的初始狀態,是解決乙個案例的關鍵。
(2)處理乙個案例的演算法過程
為方便計,我們假定序列a中的n個數為0,1,…,n-1。注意,氣泡排序的第k趟操作,總是將當前範圍(a[0..k−1])內的最大的元素推至當前範圍的最後位置a[k−1]。
除了針對趟數k=0的唯一初始狀態a[0..n−1]已經有序外,我們歸納k=k(1leqslantk
k=1時,初始狀態只能是1,…, n−1中的乙個元素不出現在自己應有的位置上,而其他元素均處於相對順序的位置上。對於1而言,它要出現在a[0]處;對於2而言,它可以出現在a[0]、a[1]處之一;…一般地,對於i(0
k=2時,初始狀態可以是1,…, n−1中的兩個元素不出現在應有的位置上,而其他元素均處於相對順序的位置上。對於0
一般地,k=k(1leqslantk
若將1~n-1中的k個數0
**bublle-sort-rounds(n, k, k, x, count) ▷k表示遞迴層次
1 if kgeqslantk ▷得到乙個積
2 then item←1
3 for i←1 to k
4 do item←(itemxi) mod 20100713
5 count←(count+item) mod 20100713
6 return
7 if k=0
8 then begin←n-1, end← k ▷頂層,x[0]的取值範圍
9 else begin←xk-1-1, end← k-k ▷k>1時,x[k]的取值範圍
10 for p←begin downto end ▷確定第k個因子
11 do xk ← p
12 bublle-sort-rounds(n, k, k+1)**
演算法1-10 計算具有n個不同元素恰做k趟操作完成排序的序列初始狀態數的過程
對測試案例資料n和k,上述過程執行如下。這是乙個遞迴過程。遞迴層次由引數k表示,表示計算乙個積中第k個因子。最頂層的呼叫應該是bublle-sort-rounds(n, k, 0, x, count),即k=0。
第1~7行當檢測到k>k時,意味著得到乙個積的所有因子。由於20100713是乙個素數,以它為模的剩餘類[3]對加法和乘法運算是封閉的,所以,可以對每一步乘法運算求關於模20100713的剩餘,也可以在將積累加到count時進行求關於模20100713的剩餘。
第7~8行if-then-else結構針對k是否為1決定第k個因子的取值範圍begin~end。
第9~12行的for迴圈完成對第k個因子xk的確定後,呼叫自身確定xk+1。
由於sum_}
解決本問題的演算法的c++實現**儲存於資料夾laboratory/bubble sort中,讀者可開啟檔案bubblesort.cpp研讀,並試執行之。
《趣題學演算法》 第1章1 5節置換與輪換
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上...
《趣題學演算法》 第0章0 4節演算法的正確性
0.4 演算法的正確性 解決乙個計算問題的演算法是正確的,指的是對問題中任意合法的輸入均應得到對應的正確輸出。大多數情況下,問題的合法輸入無法窮盡,當然就無法窮盡輸出是否正確的驗證。即使合法輸入是有限的,窮盡所有輸出正確的驗證,在實踐中也許是得不償失的。但是,無論如何,我們需要保證設計出來的演算法的...
《SOA達人迷》 第1章1 3節SOA案例分析
1.3 soa案例分析 soa達人迷 大約在150年以前,有一家名叫abc的保險公司,通過向工廠和製造商銷售保險單起家。早期沒有電腦,公司業務還算井井有條,沒有被搞得一團糟。公司的業務過程非常簡單,客戶發來信件申請保險,公司的業務人員確定利率,銷售保險,並希望不要發生著火或意外事件。abc公司繁榮了...