Github:sudoku
專案相關要求
利用程式隨機構造出N個已解答的數獨棋盤 。
輸入
數獨棋盤題目個數N(N在0和1000000之間)
輸出
隨機生成N個不重複的已解答完畢的數獨棋盤,並輸出到sudoku.txt中。在生成數獨矩陣時,左上角的第一個數為:(學號後兩位相加)% 9 + 1。
思路與程式碼
一暑假沒碰過程式碼的我,在暑假結束前一週看到了這個作業題目,腦子裡想起來的就是大一的時候敲得八皇后和馬遍歷的題目,比較類似,都是關於遞迴回溯的演算法。大致思路就是給每個格子試不同的數,找到符合條件的填下,如果不可以的就回到前一個,換一個數再試試,不行再回溯,於是有了下面的程式碼:
int count=0;//統計輸出了多少數獨
void sudoku(int i,int j)
{
for(int x=1;x<=9;x++)//給每個格子都試9個數
{
if(check(i,j,x)==1)//如果可以
{
board[i][j]=x;//就賦值
if(i==8&&j==8)//如果填滿了,就輸出
{
print();
count++;
if(count>=N) exit(-1);
return;//輸出還沒到N個,就繼續返回試其他數
}
if(j==8)//如果當前位置是某一行最後一個,就跳到下一行第一個
{
sudoku(i+1,0);
}
else//不然就跳到下一個
{
sudoku(i,j+1);
}
}
}
board[i][j]=0;
return ;//這個格子沒有一個數符合,就返回上一個格子
}
下面是判斷這個格子是否可以這個數的check函式:
int check(int row,int col,int num)//判斷是否能放
{
for(int i=0;i<9;i++)//判斷列有沒相同的
{
if(board[i][col]==num)return 0;
}
for(int j=0;j<9;j++)//判斷行有沒相同的
{
if(board[row][j]==num)return 0;
}
int x=row/3,y=col/3;
x=3*x;
y=3*y;
for(int i=0;i<3;i++)//檢查小九宮格
{
for(int j=0;j<3;j++)
{
if(board[x+i][y+j]==num)return 0;
}
}
return 1;
}
生成100W個數獨大概要52秒左右
生成的結果輸出到sudoku.txt
效能分析
用VS自帶的效能分析器進行分析,測試的生成的數獨為10W個:
PSP
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | ||
· Estimate | · 估計這個任務需要多少時間 | 800 | 1000 |
Development | 開發 | ||
· Analysis | · 需求分析 (包括學習新技術) | 120 | 130 |
· Design Spec | · 生成設計文件 | 0 | 0 |
· Design Review | · 設計複審 (和同事稽核設計文件) | 0 | 0 |
· Coding Standard | · 程式碼規範 (為目前的開發制定合適的規範) | 60 | 60 |
· Design | · 具體設計 | 90 | 120 |
· Coding | · 具體編碼 | 270 | 330 |
· Code Review | · 程式碼複審 | 60 | 60 |
· Test | · 測試(自我測試,修改程式碼,提交修改) | 90 | 90 |
Reporting | 報告 | ||
· Test Report | · 測試報告 | 120 | 110 |
· Size Measurement | · 計算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事後總結, 並提出過程改進計劃 | 60 | 60 |
合計 | 900 | 1050 |
反思與總結
這次程式碼雖然思路簡單,但是遞迴實現起來理解的意思確實很複雜,因為好久沒敲這類題,已經忘記了當時如何理解遞迴。經過一番痛苦掙扎(把之前八皇后和馬遍歷的程式碼翻出來溫習了一下),總算有點想明白,遞迴就是層層遞迴,就像一顆樹一樣,從根節點遞迴到子節點,子節點行不通,return會根節點從旁路走。其實我還想了一種方法(其實是網上看到的),就是把九宮格分成九個獨立的宮,因為每個宮都會有1-9九個數字,所以就按數字來放,比如先把1排進每個宮,接著放2,以此類推,而且在放頭尾兩個數的時候完全不用回溯,我覺得應該會減少程式碼執行復雜度,我也嘗試的敲了下,奈何學藝不精沒有成功,於是就選了這種普通的方法。這很反映了我現在的程式碼能力很弱,需要加強咯。