天天看點

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——1.2 統計分析法的實驗範例

在一時得不到事物的特征機理的情況下,我們可先通過手算或程式設計等方法測試得到一些資料(即問題的部分解),再利用數理統計知識對資料進行處理,進而得到最終的數學模型。

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——1.2 統計分析法的實驗範例

圖1.2-1給出了統計分析法的大緻流程:先從ad hoc問題的原型出發,通過手工或簡單的程式得到問題的部分解(即解集a),然後運用數理統計方法,通過部分解得到問題原型的主要屬性(大部分屬性是規律性的東西),進而建立數學模型,最後通過算法設計和程式設計得到問題的全部解(即全集i)。這裡需要注意的是:

1)因為有時候根本無法求出問題的部分解,或者無法用數理統計知識分析部分解,是以求部分解的過程和對部分解進行數理統計的過程畫的是虛線,表示不是每個資訊原型都能用統計分析法模組化。

2)所有模型對應的算法是将盲目搜尋排除在外的。因為盲目搜尋是從全集i出發求解集a的,這違背了模組化的目的。我們所讨論的統計分析法,是在對全解集i的子集a進行數理統計的基礎上建立數學模型,是以盲目搜尋不屬于統計分析法的範疇。

3)一般來說,我們可以先采用機理分析法進行分析;如果機理分析進行不下去,再考慮使用統計分析法。當然,如果問題容易找到部分簡單解,我們亦可優先考慮統計分析法。事實上,機理分析所得出的某些結論,往往可有效地運用于統計分析法;而統計分析法得出的某些規律,最終需要通過機理分析驗證其準确性。是以這兩者彼此并不是孤立的。我們在模組化的時候完全可以兩者兼用。

【1.2.1 ants】

【問題描述】

一支螞蟻軍隊在長度為l厘米的橫竿上走,每隻螞蟻的速度恒定,為1厘米/秒。當一隻行走的螞蟻到達橫竿終點的時候,它就立即掉了下去;當兩隻螞蟻相遇的時候,它們就調轉頭,并開始往相反的方向走。我們知道螞蟻在橫竿上原來的位置,但不知道螞蟻行走的方向。請計算所有螞蟻從橫竿上掉下去的最早可能的時間和最晚可能的時間。

輸入:

輸入的第一行給出一個整數,表示測試用例個數。每個測試用例首先給出兩個整數:橫竿的長度(以厘米為機關)和在橫竿上的螞蟻的數量n。接下來給出n個整數,表示每隻螞蟻在橫竿上從左端測量過來的位置,沒有特定的次序。所有輸入資料不大于1000000,資料間用空格分隔。

輸出:

對于輸入的每個測試用例,輸出用一個空格分隔的兩個數,第一個數是所有的螞蟻掉下橫竿的最早可能的時間(如果它們的行走方向選擇合适),第二個數是所有的螞蟻掉下橫竿的最晚可能的時間。

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——1.2 統計分析法的實驗範例

試題來源:waterloo local 2004.09.19

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——1.2 統計分析法的實驗範例

線上測試位址:poj 1852,zoj 2376,uva 10714

試題解析

螞蟻數的上限為1000000,爬行方向共有21000000種,這是一個天文數字,是以不可能真的去逐一枚舉螞蟻的方向。

我們先研究螞蟻少的時候的一些情況(見圖1.2-2)。

顯然,螞蟻愈多變化愈多,情況愈複雜。其實解題的瓶頸就是螞蟻相遇的情況。假如我們拘泥于“對于相遇如何處理”這個細節,将陷入無從着手的窘境。

假如出現這樣一種情況:螞蟻永遠不會相遇(即所有向左走的螞蟻都在向右走的螞蟻的左邊),那麼很容易找出o(n)的算法。

我們回過頭觀察前面給出的那個例子。我們發現相遇隻會發生在出現“”時,相遇後就變成了“”,這就相當于忽略了“相遇”這一事件。也就是說,我們可以假設這些螞蟻即使相遇了也不理睬對方而繼續走自己的路。對于問題來說,所有的螞蟻都是一樣的,并無相異之處,是以這個假設是合理的。這樣,每隻螞蟻掉落所用時間就隻有兩個取值:一個是向左走用的時間,一個是向右走用的時間。全部掉落的最早時間就是每隻螞蟻盡快掉落用時的最大值,因為這些螞蟻現在互不幹擾。同理,全部掉落的最遲時間就是每隻螞蟻盡量慢掉落用時的最大值。由此得出算法,設

li為螞蟻i在橫竿上從左端過來測量的位置(1≤i≤n);little為n隻螞蟻掉下橫竿的最早可能時間;big為n隻螞蟻掉下橫竿的最晚可能的時間。

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——1.2 統計分析法的實驗範例

本題從最簡單的情況入手,通過分析發現所有螞蟻的等價性,将“相遇後轉向”轉變為“相遇互不幹擾”,進而簡化了問題,可以輕而易舉地計算出答案。

程式清單

【1.2.2 matches game】

有一個簡單的遊戲。在這個遊戲中,有若幹堆火柴和兩個玩家。兩個玩家一輪一輪地玩。在每一輪中,一個玩家可以選擇一個堆,并從該堆取走任意根火柴(當然,取走火柴的數量不可能為0,也不可能大于所選的火柴的數量)。如果一個玩家取了火柴後,沒有火柴留下,那麼這個玩家就赢了。假設兩個玩家非常聰明,請告訴大家是否先玩的玩家會赢。

輸入由若幹行組成,每行一個測試用例。每行開始首先給出整數m(1≤m≤20),表示火柴堆的堆數;然後給出m個不超過10000000的正整數,表示每個火柴堆的火柴數量。

對每個測試用例,如果是先手的玩家赢,則在一行中輸出"yes";否則輸出"no"。

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——1.2 統計分析法的實驗範例

試題來源:poj monthly,readchild

線上測試位址:poj 2234

先考查最簡單的情況:

1)如果遊戲開始時隻有一堆火柴,則遊戲人Ⅰ通過取走所有的火柴而獲勝。

2)如果遊戲開始時有兩堆火柴,且火柴數量分别為n1和n2。

遊戲人取得勝利并不在于n1和n2的值具體是多少,而是取決于它們是否相等。

若n1≠n2,則遊戲人Ⅰ從大堆中取走火柴使得兩堆火柴數量相等,于是遊戲人Ⅰ以後每次取子的數量與遊戲人Ⅱ相等而最終獲勝。

若n1=n2,則遊戲人Ⅱ隻要按着遊戲人Ⅰ取子的數量在另一堆中取相等數量的火柴,最終獲勝者将會是遊戲人Ⅱ。

這樣,兩堆的取子獲勝政策就已經找到了。現在的問題是,如何從兩堆的取子政策擴充到任意堆數中呢?

3)任意堆數。

首先來回憶一下,每個正整數都有一個對應的二進制數,例如:57(10)=111001(2),即57(10)=25+24+23+20。于是,我們可以認為每一堆火柴數由2的幂數的子堆組成。這樣,含有57枚火柴的大堆就能看成是分别由數量為25、24、23、20的4個子堆組成。

現在考慮各大堆大小分别為n1,n2,…,nk的取子遊戲。将每一個數ni表示為其二進制數(數的位數相等,不等時在前面補0):n1=as…a1a0

n2=bs…b1b0

  …

nk=ms…m1m0如果每一種大小的子堆數都是偶數,我們就稱取子遊戲是平衡的,而對應位相加是偶數的稱為平衡位,否則稱為非平衡位。是以取子遊戲是平衡的,當且僅當as+bs+…+ms是偶數

… 

a1+b1+…+m1是偶數

a0+b0+…+m0是偶數這裡之是以提出取子遊戲平衡的概念,是因為當一方處于平衡狀态(非平衡狀态)時,對方總能夠通過下一輪取子使之變成非平衡狀态(平衡狀态)。而赢方的最後狀态是s+1位都為平衡位(全0)。于是,我們猜想出一個獲勝政策:

遊戲人Ⅰ能夠在非平衡取子遊戲中取勝,而遊戲人Ⅱ能夠在平衡的取子遊戲中取勝。

下面通過統計分析方法證明上述猜想。先以一個兩堆火柴的取子遊戲作為試驗:

設遊戲開始時遊戲處于非平衡狀态。這樣,遊戲人Ⅰ就能通過一種取子方式(見下面的歸納)使得他取子後留給遊戲人Ⅱ的是一個平衡狀态下的遊戲,接着無論遊戲人Ⅱ如何取子,再留給遊戲人Ⅰ的一定是一個非平衡狀态下的遊戲(隻有二進制情形下能達到這種必然的轉變,因為任何取子均會改變一個或多個位置上的比特值,而任何一個比特值的改變要麼是0變1要麼是1變0,這都會改變奇偶性。但是在多進制情形下,某一位置上2變0或3變1就不會改變平衡性。換句話說,平衡性隻在二進制下定義,定義多進制下的平衡性沒有意義),如此反複進行,當遊戲人Ⅱ在最後一次平衡狀态下取子後,遊戲人Ⅰ便能一次性取走所有的火柴而獲勝。而如果遊戲開始時遊戲處于平衡狀态,那根據上述方式取子,最終遊戲人Ⅱ能獲勝。

接下來,應用此獲勝政策來考慮4堆火柴的取子遊戲。其中各堆的大小分别為7,9,12,15枚火柴,用二進制表示各數分别為:0111,1001,1100和1111,于是可得到表1.2-1。

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——1.2 統計分析法的實驗範例

由取子遊戲的平衡條件可知,此遊戲是一個非平衡狀态的取子遊戲,是以,遊戲人Ⅰ在按獲勝政策進行取子遊戲下将一定能夠取得最終的勝利。具體做法有多種,遊戲人Ⅰ可以從大小為12的堆中取走11枚火柴,使得遊戲達到平衡(如表1.2-2)。

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——1.2 統計分析法的實驗範例

遊戲人Ⅰ将非平衡狀态轉為平衡狀态的方法是:将某一行的非平衡位取反并使得取反之後該行的值小于取反之前的值。取子個數為取反前後數值之差。

之後,無論遊戲人Ⅱ如何取子,遊戲人Ⅰ在取子後仍使得遊戲達到平衡。

同樣的道理,遊戲人Ⅰ也可以選擇大小為9的堆并取走5枚火柴而剩下4枚,或者遊戲人Ⅰ從大小為15的堆中取走13枚而留下2枚。

歸根結底,取子遊戲的關鍵在于遊戲開始時遊戲處于何種狀态(平衡或非平衡)和第一個遊戲人是否能夠按照取子遊戲的獲勝政策來進行遊戲。由此得出算法:

n堆火柴數量對應的n個二進制數,連續進行n-1次異或運算。若結果非0,則說明存在非平衡位,先手的玩家赢;若結果為0,則說明所有位平衡,後手的玩家赢。

繼續閱讀