Github倉庫地址https://github.com/JoekrLSJ/031702444node
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 60 | 30 |
Estimate | 估計這個任務須要多少時間 | 1440 | 1200 |
Development | 開發 | 180 | 240 |
Analysis | 需求分析 (包括學習新技術) | 60 | 120 |
Design Spec | 生成設計文檔 | 60 | 30 |
Design Review | 設計複審 | 120 | 60 |
Coding Standard | 代碼規範 (爲目前的開發制定合適的規範) | 120 | 60 |
Design | 具體設計 | 60 | 60 |
Coding | 具體編碼 | 120 | 180 |
Code Review | 代碼複審 | 120 | 60 |
Test | 測試(自我測試,修改代碼,提交修改) | 120 | 120 |
Reporting | 報告 | 60 | 30 |
Test Repor | 測試報告 | 120 | 150 |
Size Measurement | 計算工做量 | 60 | 30 |
Postmortem & Process Improvement Plan | 過後總結, 並提出過程改進計劃 | 180 | 150 |
合計 | 1440 | 1200 |
讀完題目,第一個想法就是DFS+回溯,總結了一下宮格的特徵,發現能夠分紅兩類,一類是有宮的(四六八九宮格),一類是無宮的,即只要判斷行列是否衝突(三五七宮格)。題目說是惟一解,因此每次只要填入的是沒有衝突的數字,最後能所有填完,就是答案。git
Soduku.cpp 1.0github
要點說明編程
這是最初的版本,先從簡單的三五七宮格入手,只要設置行列標記,位置不衝突便可填入,填不完回溯,最後填完就是答案。
設置標記函數
int Soduku_map_row[maxn][maxn]; //行標記,未填入爲0 int Soduku_map_column[maxn][maxn]; //列標記,未填入爲0 int flag; //填完標記
用結構體隊列存儲待填格子行列位置工具
struct node { int nrow; int ncolumn; } blank_node[maxn*maxn],pos_node[maxn]; //記錄未填入宮格的行列座標
求解方法:DFS+回溯函數post
Soduku_find()性能
調用這個函數計算三五七宮格數獨單元測試
void Soduku_find(int now) { if (flag) return; if (now == blank_node_count + 1) { flag = 1; return; } int x = blank_node[now].nrow; int y = blank_node[now].ncolumn; rep(i, 1, n) { if ((!Soduku_map_row[x][i]) && (!Soduku_map_column[y][i])) { Soduku_map_row[x][i] = 1; //行不衝突 Soduku_map_column[y][i] = 1; //列不衝突 Soduku_map[x][y] = i; //這個格子填入i Soduku_find1(now + 1); //填下一個格子 if (flag) return; //填完退出 Soduku_map_row[x][i] = 0; //行標記 Soduku_map_column[y][i] = 0; //列標記 } } }
輸入函數 Soduku_input()學習
void Soduku_input() { rep(i, 1, n) { rep(j, 1, n) { cin >> Soduku_map[i][j]; if (Soduku_map[i][j] == 0) { blank_node_count++; blank_node[blank_node_count].nrow = i; blank_node[blank_node_count].ncolumn = j; } else { Soduku_map_row[i][Soduku_map[i][j]] = 1; Soduku_map_column[j][Soduku_map[i][j]] = 1; if (!(n == 3 || n == 5 || n == 7)) { int pos = getpostion(i, j, pos_node[n].nrow, pos_node[n].ncolumn, n); Soduku_positon[pos][Soduku_map[i][j]] = 1; } } } } }
輸出函數 Soduku_outputput()
void Soduku_output() { rep(i, 1, n) { rep(j, 1, n) { if (j != n)cout << Soduku_map[i][j] << " "; else cout << Soduku_map[i][j]; } cout << endl; } cout << endl; }
Soduku.cpp 2.0
因爲四六八九宮格每種宮格的行列劃分的方法不同,因此設計了一個函數輸入待填位置的行列座標和小宮格行列數以及大宮格的邊長就能算出當前位置在哪一個宮格。
宮格函數int getpostion(int,int,int,int,int)
int getpostion(int x, int y, int row, int column, int n) { return (x - 1) / row * (n / column) + (y - 1) / column + 1; }
舉個例子,在九宮格(5,4)位於第5宮格,(5 - 1)/ 3 *(9 / 3)+ (4 -1)/ 3 +1=5。每一個宮格3行3列,(x - 1)/ row算出在第幾行的宮格,乘上每行有(n / cloumn)個宮格,再加上在第幾列的宮格上(y - 1) / column + 1,最後就是所在宮格的位置。
加入宮標記
Soduku_positon[maxn][maxn]; //宮標記,未填入爲0
增長void Soduku_find2(int)函數,計算四六八九宮格數獨。
void Soduku_find2(int now) { if (flag) return; if (now == blank_node_count + 1) { flag = 1; return; } int x = blank_node[now].nrow; int y = blank_node[now].ncolumn; int pos = getpostion(x, y, pos_node[n].nrow, pos_node[n].ncolumn, n); rep(i, 1, n) { if ((!Soduku_map_row[x][i]) && (!Soduku_map_column[y][i]) && (!Soduku_positon[pos][i])) { Soduku_map_row[x][i] = 1; //行不衝突 Soduku_map_column[y][i] = 1; //列不衝突 Soduku_positon[pos][i] = 1; //宮不衝突 Soduku_map[x][y] = i; //這個格子填入i Soduku_find2(now + 1); //填下一個格子 if (flag) return; //填完退出 Soduku_map_row[x][i] = 0; //行標記 Soduku_map_column[y][i] = 0; //列標記 Soduku_positon[pos][i] = 0; //宮標記 } } }
(4)單元測試樣例
三宮格
四宮格
五宮格
六宮格
七宮格
八宮格
九宮格
後面簡單寫了個批處理文件test.bat測試一下輸出結果的正確性。
test.bat代碼
@echo off title "Black Box Test" for %%i in (3,4,5,6,7,8) do ( echo 當前測試第m%%in5組: echo 5 %%i > input.txt type m%%in5.txt >> input.txt Sudoku fc output.txt m%%in5_answer.txt /W pause >nul del input.txt del output.txt )
若是輸入文件output.txt和m3n5answer.txt內容一致答案正確就會顯示「找不到相異處」,反之會提示兩個文件不同的地方。
(5)異常處理
在編譯的時候一直出現C4996的錯誤沒法消除,查了一下是由於freopen和預處理器的問題,經過在預處理器最上方,也就是第一行添加以下代碼,便可解決該錯誤:
#pragma warning(disable:4996)
(6)性能分析
此次題目難度不是很難,主要的時間都花在了熟悉VS 2017的使用,學習如何建立項目,初步學習使用性能分析工具,如今還不是很熟練,後面要熟練掌握。此次還學習了PSP流程,順便複習了一下int main(int argc,int *argv[])的使用方法。最後熟悉了在Github上面管理代碼的方法和流程。