1、github地址:https://github.com/kinglc/sudoku1943
2、解題思路:項目包括 輸入與輸出(文件讀寫、命令行),生成不重復終局,解數獨三個部分。
(1)輸入與輸出
文件讀寫和命令行雖然都不熟,但稍微百度就完全可以解決。
(2)生成不重復終局
先隨便寫了一個數獨終局
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 3
7 8 9 1 2 3 4 5 6
2 3 4 5 6 7 8 9 1
5 6 7 8 9 1 2 3 4
8 9 1 2 3 4 5 6 7
3 4 5 6 7 8 9 1 2
6 7 8 9 1 2 3 4 5
9 1 2 3 4 5 6 7 8
只需要生成一定數量的數獨終局從簡單的入手就好,上圖第一行是隨手寫,后8行都可以看做根據第一行左移得到,第一行全排列有8!=40320種,然后交換2-3(因為數據只要求1e6,可以不 考慮),4-6,7-9行,再乘3!×3!,結果略大於1e6。
(3)解數獨
本來試着看了一下dancing links算法,但十字鏈表似乎好麻煩的樣子,於是老老實實用dfs暴力寫完了。
3、代碼設計
(1)函數功能
int main(int ,char *) :獲取命令行參數,進入不同處理函數
void createFinal():參數為-c時:生成終局存入數組,並調用output(int,int)函數
void workout(int):參數為-s時:通過深搜得出終局,用check(int,int)函數判斷,並調用output(int,int)函數
bool check(int,int):判斷在該處填的數字是否合理
void output(int,int):根據參數所代表的輸出順序輸出終局
(2)關鍵函數
生成終局:

void createFinal() { int tmp[9] = { 8,9,1,2,3,4,5,6,7 };//tmp表示第一行數字 int i, j, k, moveleft[8] = { 3,6,1,4,7,2,5,8 }; //moveleft表示2-9行在第1行基礎上整體左移位數 for (i = 0; i < 40320; i++) //8!=40320 { memcpy(numBoard[0], tmp, sizeof(tmp)); //將第1行左移生成2-9行 for (j = 0; j < 8; j++) for (k = 0; k < 9; k++) numBoard[j + 1][k] = numBoard[0][(k + moveleft[j]) % 9];//初始圖完成 //調換4-6,7-9行 for (j = 0; j < 6; j++) for (k = 0; k < 6; k++) { output(j, k); if (!--testnum) return; } next_permutation(tmp + 1, tmp + 9);//重置第一行 } return; }
解數獨:

void workout(int pos)//深搜 { if (pos == 81) { output(0, 0); flag = 1; //標記是否輸出過 return; } int i, x, y; x = pos / 9; y = pos % 9; if (!numBoard[x][y]) { for (i = 1; i <= 9; i++) { if (cnt[i - 1] == 9) continue; numBoard[x][y] = i;//填充數字 cnt[i - 1]++; if (check(pos, i)) workout(pos + 1); if (flag) //該數獨已解完 return; cnt[i - 1]--; numBoard[x][y] = 0; } } else workout(pos + 1); }
(3)單元測試
命令行參數判定:-c, -s, -abc
運行情況判定:-c 1, -c 1000, -c 1000000, -s 文件路徑(其中包含1、1000、1000000個用例)
4、運行分析
(1)生成1000個數獨終局
(2)解1000個20-40個空格的數獨
(3)優化
在生成終局中,本來是用了三次全排列分別對第一行8個數字、第4-6行、7-9行處理,后優化為用print[6][3]={ 0,1,2,0,2,1,1,2,0,1,0,2,2,1,0,2,0,1 }存入全排列數,在output函數中處理輸出。

void output(int mid,int last) { int i, j, k, row; int order[3] = { 0 }; order[1] = mid; order[2] = last; for (i = 0; i < 3; i++)//輸出第i個三行 for (j = 0; j < 3; j++) { row = print[order[i]][j] + 3 * i; for (k = 0; k < 8; k++) output_file << numBoard[row][k] << " "; output_file << numBoard[row][8]<<endl; } output_file << endl; }
5、PSP
PSP2.1 |
Personal Software Process Stages |
預估耗時(分鍾) |
實際耗時(分鍾) |
Planning |
計划 |
30 |
30 |
·Estimate |
·估計這個任務需要多少時間 |
30 |
30 |
Development |
開發 |
1080 |
1080 |
·Analysis |
·需求分析(包括學習新技術) |
120 |
120 |
·Design Spec |
·生成設計文檔 |
120 |
90 |
·Design Review |
·設計復審 |
30 |
30 |
·Coding Standard |
·代碼規范 |
30 |
30 |
·Design |
·具體設計 |
180 |
180 |
·Coding |
·具體編碼 |
540 |
540 |
·Code Review |
·代碼復審 |
30 |
30 |
·Test |
·測試 |
30 |
60 |
Reporting |
報告 |
90 |
90 |
·Test Report |
·測試報告 |
40 |
40 |
·Size Measurement |
·計算工作量 |
10 |
10 |
·Postmortem&Process Improvement Plan |
·事后總結並提出過程改進計划 |
40 |
40 |
|
合計 |
1200 |
1200 |