天天看點

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——2.2 篩選法模拟的實驗範例

模拟過程中可能産生的所有解組成一個篩。篩選法模拟即先從題意中找出限制條件,然後将篩中的每一個可能解放到限制條件的過濾器上,一次一次地将不符合條件的解過濾掉,最後沉澱在篩中的即為問題的解。

篩選法模拟的結構和思路簡明、清晰,但帶有盲目性,是以時間效率并不一定令人滿意。篩選法模拟的關鍵是找準限制條件,任何錯誤和疏漏都會導緻模拟失敗。

【2.2.1 the game】

【問題描述】

五子棋遊戲是由兩名玩家在一個19*19的棋盤上玩的遊戲。一名玩家執黑,另一名玩家執白。遊戲開始時棋盤為空,兩名玩家交替放置黑色棋子和白色棋子。執黑者先走。棋盤上有19條水準線和19條垂直線,棋子放置在直線的交點上。

水準線從上到下标記為1,2,…,19,垂直線從左至右标記為1,2,…,19。

這一遊戲的目标是把5個相同顔色的棋子沿水準、垂直或對角線連續放置。是以,在圖2.2-1中執黑的一方獲勝。但是,如果一個玩家将超過五個相同顔色的棋子連續放置,也不能判赢。 

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——2.2 篩選法模拟的實驗範例

基于這一遊戲的棋盤情況,請寫一個程式,确定是白方赢了比賽,還是黑方赢了比賽,或者是還沒有任何一方赢了比賽。輸入資料保證不可能出現黑方和白方都赢的情況,也沒有白方或黑方在多處獲勝的情況。

輸入:

輸入的第一行包含一個整數t(1≤t≤11),表示測試用例的數目。接下來給出每個測試用例,每個測試用例19行,每行19個數,黑棋子辨別為1,白棋子辨別為2,沒有放置棋子則辨別為0。

輸出:

對每個測試用例,輸出一行或兩行。在測試用例的第一行輸出結果,如果黑方獲勝,則輸出1;如果白方獲勝,則輸出2;如果沒有任何一方能獲勝,則輸出0。如果黑方或白方獲勝,則在第二行給出在5個連續的棋子中最左邊棋子的水準線編号和垂直線編号(如果5枚連續的棋子垂直排列,則選最上方棋子的水準線編号和垂直線編号)。

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——2.2 篩選法模拟的實驗範例

試題來源:acm tehran sharif 2004 preliminary

線上測試位址:poj 1970,zoj 2495

試題解析

初始時所有棋子組成一個篩子。我們由上而下、由左而右掃描每個棋子,分析其k方向的相鄰棋子(0≤k≤3,0≤i,j≤18,見圖2.2-2)。 

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——2.2 篩選法模拟的實驗範例

過濾器中“赢”的限制條件是:

1)(i,j)k的相反方向的相鄰格(x,y)不同色。

2)(i,j)k方向延伸5格在界内。

3)從(i,j)開始,沿k方向連續5格同色且第6格不同色。

若(i,j)的棋子滿足上述限制條件,其顔色所代表的一方赢,(i,j)即為赢方5個連續的同色棋子中首枚棋子的位置;若檢測了4個方向,(i,j)的棋子依然不滿足限制條件,則被過濾掉。

若過濾了篩中的所有棋子後篩子變空,則說明沒有任何一方能獲勝。

程式清單

【2.2.2 game schedule required】

sheikh abdul真正熱愛足球,是以你最好不要問他為著名的球隊進入年度錦标賽花了多少錢。當然,他花了這麼多錢,就是想看到某些球隊彼此間的比賽。他拟定了他想看到的所有比賽的完整清單。現在請按以下規則将這些比賽配置設定到某些淘汰賽的輪次中:

在每一輪中,晉級的每支球隊最多隻進行一場比賽。

如果有偶數支晉級這一輪的球隊,那麼每支球隊隻進行一場比賽。

如果有奇數支晉級這一輪的球隊,那麼恰好有一支球隊沒有進行比賽(它優先用外卡晉級下一輪)。

每場比賽的優勝者晉級下一輪,失敗者被淘汰出錦标賽。

如果隻有一支球隊,那麼這支球隊就被宣布為錦标賽的優勝者。

可以證明,如果有n支球隊參加錦标賽,那麼直至産生比賽優勝者,恰好有n-1場比賽。顯然,在第一輪後,有的應該要參加下一輪比賽的球隊可能會被淘汰,為了防止這種情況,對于每場比賽,還必須知道哪支球隊會赢。

輸入包含若幹測試用例,每個測試用例首先給出一個整數n(2≤n≤1000),表示參加錦标賽的球隊的數目。然後的n行給出參加錦标賽的球隊的隊名。本題設定每個球隊的隊名可以由多達25個英文字母的字元組成('a'~'z'或'a'~'z')。

接下來的n-1行給出sheikh想要看的比賽(按任何順序)。每行由要進行比賽的兩支球隊的隊名組成。本題設定總是可以找到一個包含給出比賽的錦标賽日程。

測試用例結束後,給出一個0。

對于每個測試用例,輸出一個分布在多個輪次中的比賽日程。

對于每一輪,首先在一行中輸出"round #x"(其中x表示第幾輪),然後輸出在這一輪中的比賽形式:"a defeats b",其中a是晉級隊的隊名,b是被淘汰隊的隊名。如果在這一輪需要外卡,則在這一輪最後一場比賽後,輸出"a advances with wildcard",其中a是獲得外卡的球隊的隊名。在最後一輪之後,按如下格式輸出優勝隊,在每個測試用例之後輸出一個空行。

《算法設計程式設計實驗:大學程式設計課程與競賽訓練教材》——2.2 篩選法模拟的實驗範例

試題來源:ulm local 2005

線上測試位址:poj 2476,zoj 2801

可能的赢方組成一個篩子,初始時每個球隊在篩中。

我們首先計算sheikh想要看的n-1場比賽中每場比賽的兩個球隊編号a[i]和b[i](1≤i≤n-1),累計每個球隊比賽的場次數cnt[i](1≤i≤n)。然後從第一輪次開始,計算分布在每個輪次中比賽的日程。由于每一輪的比賽都是sheikh想要看的,是以若目前比賽的兩個球隊中僅有一個球隊沒有比賽完,則該球隊赢。由此得出過濾器中“保留球隊”的限制條件:

1)sheikh想要看的比賽中的兩個球隊不在目前輪次。

2)目前輪次sheikh想要看的比賽中需要進入下一輪的球隊。

滿足上述條件的球隊留在篩中。在進入第一輪前,所有球隊都在篩中。每個輪次的比賽場次數為進入該輪次前篩中的球隊數2。

反複進行如下過濾,直至篩中僅剩一支球隊為止:

順序搜尋sheikh想要看的每場比賽i(1≤i≤n-1):

若a[i]和b[i]在篩中,且兩隊中至少有一支隊伍隻能比一場,則這兩個球隊比賽1場,兩隊剩餘的比賽場次數-1;在篩中濾去這兩個球隊(避免球隊在目前輪次比賽兩場)。若僅存在1個可進入下一輪的球隊,則該隊赢本場比賽;若兩隊都不能進入下一輪,則産生錦标賽的優勝者。

若比賽完目前輪次的所有場次,則新增一個輪次,新輪次的比賽場次數為篩中的球隊數2,向篩中還有比賽的球隊發放外卡,篩外未比賽完的球隊重新回到篩裡,以進入新一輪。