【程式設計題】(滿分33分)
「數獨」是當下炙手可熱的智力遊戲。一般認為它的起源是「拉丁方塊」,是大數學家尤拉於2023年發明的。
如圖[1.jpg]所示:6x6的小格被分為6個部分(圖中用不同的顏色區分),每個部分含有6個小格(以下也稱為分組)。
開始的時候,某些小格中已經填寫了字母(abcdef之一)。需要在所有剩下的小格中補填字母。
全部填好後,必須滿足如下約束:
1. 所填字母只允許是a,b,c,d,e,f 中的某乙個。
2. 每行的6個小格中,所填寫的字母不能重複。
3. 每列的6個小格中,所填寫的字母不能重複。
4. 每個分組(參見圖中不同顏色表示)包含的6個小格中,所填寫的字母不能重複。
為了表示上的方便,我們用下面的6階方陣來表示圖[1.jpg]對應的分組情況(組號為0~5):
000011
022013
221113
243333
244455
445555
用下面的資料表示其已有字母的填寫情況:
02c03b
05a20d
35e53f
很明顯,第一列表示行號,第二列表示列號,第三列表示填寫的字母。行號、列號都從0開始計算。
一種可行的填寫方案(此題剛好答案唯一)為:
e f c b d a
a c e d f b
d a b e c f
f b d c a e
b d f a e c
c e a f b d
你的任務是:編寫程式,對一般的拉丁方塊問題求解,如果多解,要求找到所有解。
【輸入、輸出格式要求】
使用者首先輸入6行資料,表示拉丁方塊的分組情況。
接著使用者輸入乙個整數n (n<36), 表示接下來的資料行數
接著輸入n行資料,每行表示乙個預先填寫的字母。
程式則輸出所有可能的解(各個解間的順序不重要)。
每個解占用7行。
即,先輸出乙個整數,表示該解的序號(從1開始),接著輸出乙個6x6的字母方陣,表示該解。
解的字母之間用空格分開。
如果找不到任何滿足條件的解,則輸出「無解」
例如:使用者輸入:
000011
022013
221113
243333
244455
445555
602c
03b05a
20d35e
53f則程式輸出:
1e f c b d a
a c e d f b
d a b e c f
f b d c a e
b d f a e c
c e a f b d
再如,使用者輸入:
001111
002113
022243
022443
544433
555553
704b
05a13d
14c24e
50c51a
則程式輸出:
1d c e f b a
e f a d c b
a b f c e d
b e d a f c
f d c b a e
c a b e d f
2d c e f b a
e f a d c b
a d f b e c
b e c a f d
f b d c a e
c a b e d f
3d c f e b a
a e b d c f
f d a c e b
b f e a d c
e b c f a d
c a d b f e
4d c f e b a
b e a d c f
a d c f e b
f b e a d c
e f b c a d
c a d b f e
5d c f e b a
e f a d c b
a b c f e d
b e d a f c
f d b c a e
c a e b d f
6d c f e b a
e f a d c b
a b d f e c
b e c a f d
f d b c a e
c a e b d f
7d c f e b a
e f a d c b
a d b f e c
b e c a f d
f b d c a e
c a e b d f
8d c f e b a
f e a d c b
a d b c e f
b f e a d c
e b c f a d
c a d b f e
9d c f e b a
f e a d c b
a f c b e d
b d e a f c
e b d c a f
c a b f d e
【注意】
請仔細除錯!您的程式只有能執行出正確結果的時候才有機會得分!
在評卷時使用的輸入資料與試卷中給出的例項資料可能是不同的。
請把所有函式寫在同乙個檔案中,除錯好後,拷貝到【考生資料夾】下對應題號的「解答.txt」中即可。
相關的工程檔案不要拷入。
源**中不能使用諸如繪圖、win32api、中斷呼叫、硬體操作或與作業系統相關的api。
允許使用stl類庫,但不能使用mfc或atl等非ansi c++標準的類庫。
例如,不能使用cstring型別(屬於mfc類庫);例如,不能使用randomize, random函式(不屬於ansi c++標準)
分析:本題思路很簡單,就是dfs暴搜,但是如果只是單純的暴搜,在最後的時候再進行每行每列和每組的重複性判斷,那麼程式的效率會變得非常低,這時候就需要進行剪枝。對於剪枝,也是有很多方法的,首先dfs是通過對6*6的矩陣從左到右,從上到下的對每個方格依次放入'a'~'f'六個字母,這樣的話,我們是先行遍歷,所以每一行結束可以進行行的重複性判斷,然後最後在6*6個方格全部放入字母後,進行列和組的重複性判斷。但是這個剪枝方法,還是比較低效的。
繼續優化的話,我們使用三個陣列usedlie,usedhang,usedzu來分別存放每列,行,組中已經使用的字母,具體例如usedlie[i][j]表示第i列的第j個字母(即'a'+j)已經使用了,這樣我們就可以在每次對方格中的資料進行賦值時,都進行行,列,組的非重複性選擇。這種方法,可以大大提高程式的效率。
此外,本題還有幾個小技巧:
1.我們並不是直接將字母'a'~'f'放入方格,而是放入數字0~5,因為對於數字的操作顯然比操作字元簡單一些,最後在輸出的時候,只需要 數字+'a'即可。
2.對於組的存放,並不像行列一樣直接通過方格的位置橫縱座標就能獲得,我們在輸入的時候,就將屬於第i組的方格[x][y]經過矩陣展開後,將結果放在zu[i]中,也就是說
zu[i][j]=x*6+y表示座標為[x][y]的方格陣列第i組,且是其第j個元素。(但是這個技巧是在上述提到的最後進行組重複性判斷下使用,便於快速找到每組的方格,而在使用usedzu
進行重複性判斷的時候,該陣列就不需要了)
3.對於初始化已經放入字母的方格,我們可以使用already陣列,already[i][j]=1就表示指定的方格中已經放入了字母,這樣,在進行dfs遍歷到該方格時,直接跳過遍歷下乙個方格即可。
以下即為原始碼:
#include#includeusing namespace std;
//int zu[6][6]; //zu[i][j]表示第i組的第j個位置的下標轉換結果
//int pos[6]=; //pos[i]表示下乙個第i組的位置放在zu[i]中的位置,即zu[i][pos[i]]
//char test[7][7]=;
int res[6][6]; //res表示0~5數字形式的結果
bool already[6][6]; //already表示指定位置的元素已經被賦值
int count=0; //count表示已找到的結果數
bool usedlie[6][6]; //used[i][j]表示下標為i的列是否已經使用了數字j
bool usedhang[6][6]; //used[i][j]表示下標為i的行是否已經使用了數字j
bool usedzu[6][6];
int zuadj[6][6]; //zuadj表示指定位置的元素所在的組編號
void print()
if(already[x][y]==true)
else}}}
int main() }
int n;
cin>>n;
for(int i=0;i>str;
int x=str[0]-'0';
int y=str[1]-'0';
int value=str[2]-'a';
res[x][y]=value;
already[x][y]=true;
usedlie[y][value]=true;
usedhang[x][value]=true;
usedzu[zuadj[x][y]][value]=true;
} dfs(0,0);
return 0;
}
ps:雖然拿到這題就有了思路-dfs加剪枝,但是**實現起來卻著實浪費了我不少時間,尤其是在剪枝的優化時,**也是不斷除錯了好長時間。但是,說實話,這樣不斷除錯,一點點優化,最後有結果的感覺,真是棒棒哦~**也是寫的酣暢淋漓~
藍橋杯 方塊填數 DFS搜尋
數獨 是當下炙手可熱的智力遊戲。一般認為它的起源是 拉丁方塊 是大數學家尤拉於1783年發明的。如圖 1.jpg 所示 6x6的小格被分為6個部分 圖中用不同的顏色區分 每個部分含有6個小格 以下也稱為分組 開始的時候,某些小格中已經填寫了字母 abcdef之一 需要在所有剩下的小格中補填字母。全部...
五星填數 藍橋杯決賽
如 圖1.png 的五星圖案節點填上數字 1 12,除去7和11。要求每條直線上數字和相等。如圖就是恰當的填法。請你利用計算機搜尋所有可能的填法有多少種。注意 旋轉或映象後相同的算同一種填法。請提交表示方案數目的整數,不要填寫任何其它內容。典型暴力,不過由於太多的數,所以用for不是太好的選擇 可以...
藍橋杯 方格填數
方格填數 如下的10個格仔 如果顯示有問題,也可以參看 圖1.jpg 填入0 9的數字。要求 連續的兩個數字不能相鄰。左右 上下 對角都算相鄰 一共有多少種可能的填數方案?請填寫表示方案數目的整數。注意 你提交的應該是乙個整數,不要填寫任何多餘的內容或說明性文字。include include in...