做業題目地址:軟件工程實踐 2017 第二次做業
課程博客目錄:軟工課程做業博客目錄-031502627
項目 GitHub 地址:egbertwang / Sudokuhtml
項目 | more |
---|
每一行、每一列、每個粗線宮(3*3)內的數字均含1-9,不重複。java
n //數獨棋盤個數
git
隨機生成N個不重複的已解答完畢的數獨棋盤,並輸出到sudoku.txt中,而且左上角的第一個數爲:(學號後兩位相加)% 9 + 1。即 ( 2 + 7 ) % 9 + 1 = 1。github
首先我以前從未作過數獨題目,也不知道數獨的規則。從題目描述中瞭解到了數獨棋盤要知足的條件,要每一行、每一列、每個九宮格都有 1-9 不重複的出現,並且左上角必須是 1(我本身的學號算出來的)。算法
那麼接下來就要找一些數獨題目來作一下了。我找了一些在線生成數獨題目的網站,發現本身並不能作出來,並且根據個人搜索,正常填空的方法並不適合完整的數獨棋盤的生成,遂放棄。
在我 Google 的時候發現了一位博主用 Swing 和 Java 寫的終盤生成法,分別使用矩陣轉換法 [1] 和隨機法 [2]。矩陣轉換法就是將幾個已生成的終盤數獨棋盤做爲模板,隨機選取並進行隨機的矩陣變換來生成新的數獨棋盤。經計算一個終盤棋盤可經矩陣變換生成 1119744 個不重複且正確的棋盤,剛恰好知足題目 n < 1000000 的要求。當咱們事先輸入幾個不一樣的棋盤,而且生成時隨機選取並進行隨機的一系列變換就能夠生成足夠多的棋盤。可是這個方法顯然不夠隨機,我在進行了其餘的嘗試以後都不成功纔會回來採用這個較爲簡單的方法。同時我也認識到本身程序設計的能力較差,還須要大量的練習,以後會抽時間作一些acm題目來訓練本身。文中的隨機生成法是隨機生成一行來碰運氣,我認爲不妥,並且效率較爲低下。我又考慮了將每一個數依次填入九宮格的方法,好比說先將所有的 1 填入,再將所有的 2 填入,每次填入作一次行列的判斷,若可行就填入,不可行就換個地方,直到沒法放入,就所有清除,從頭開始。再以此類推。我認爲這個方法比較穩妥,若是生成的數量多的話能夠考慮將已生成的棋盤作矩陣變換,一樣是隨機而且不重複的,並且更節省時間。固然還要寫出來代碼看看。編程
首先,要有一個生成一系列隨機座標的函數,生成如 (x, y) 的座標組。x 表示橫座標,y 表示縱座標。
接着進行判斷,當該座標左邊,上邊都不重複的話就填入,不然將有衝突的座標 + 1,依次循環,正常狀況下總能夠填入。當出現沒法填入的狀況時,若當前填入的數是 a,則將所有的 a、a - 一、a - 2 置 0,從 a - 2 開始填入,當重複次數到達規定閾值的時候還不能成功填入,就所有清楚,從頭開始。此處爲溯回的思想。此時不考慮矩陣變換,那麼程序大概的流程以下:數組
當前填入數 a = 1; 檢查當前九宮格位置(x,y), 若 x = y = 1 則填入最左上角一格, 不然生成隨機座標 檢查隨機座標是否合法, // Judge() 若不合法則將對應座標 + 1, 若兩次內成功填入,進入下一個九宮格,重複, 若沒法填入,則清除以前 a , a - 1, a - 2, 從這裏從新填入,直到所有的數所有成功填入, 輸出,初始化,進入下一次循環
因爲算法較爲複雜,因此從裏向外來實現算法。
首先,定義Sudoku[3][3]
,Pos_s[2]
,Pos_l[2]
分別爲保存數獨棋盤、隨機座標的數組 和 當前九宮格座標。定義#define random(x) (rand() % x + 1)
來生成指定範圍內的隨機數。
接着,用Judge()
函數來判斷是否可填入:dom
bool Judge() //判斷是否能夠填入 返回爲 1 則可填入 { int i, j; bool flag = 1; // If Pos is avalible, set flag = 1, else set flag = 0 for(i = 0; i < Pos_s[0] + Pos_l[0] * 3; i++) { if(Sudoku[i][Pos_s[1] + Pos_l[1] * 3] == a) { flag = 0; break; } } if(flag == 1) { for(j = 0; j < Pos_s[1] + Pos_l[1] * 3; j++) { if(Sudoku[Pos_s[0] + Pos_l[0] * 3][j] == a) { flag = 0; } } } return flag; }