藍橋杯決賽之方塊填數

2021-07-31 04:59:52 字數 4947 閱讀 7739

【程式設計題】(滿分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...