個人項目
阿新 • • 發佈:2017-09-26
planning write 調用 也不能 分鐘 tag 最終 dev 更新
個人項目博客
1.github項目地址
https://github.com/zhaobs-yu/sudoku
2.PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 5 | 5 |
· Estimate | · 估計這個任務需要多少時間 | 5 | 5 |
Development | 開發 | 670 | 910 |
· Analysis | · 需求分析 (包括學習新技術) | 120 | 240 |
· Design Spec | · 生成設計文檔 | 5 | 5 |
· Design Review | · 設計復審 (和同事審核設計文檔) | 2 | 2 |
· Coding Standard | · 代碼規範 (為目前的開發制定合適的規範) | 3 | 3 |
· Design | · 具體設計 | 60 | 120 |
· Coding | · 具體編碼 | 300 | 360 |
· Code Review | · 代碼復審 | 60 | 60 |
· Test | · 測試(自我測試,修改代碼,提交修改) | 120 | 120 |
Reporting | 報告 | 55 | 55 |
· Test Report | · 測試報告 | 30 | 30 |
· Size Measurement | · 計算工作量 | 5 | 5 |
· Postmortem & Process Improvement Plan | · 事後總結, 並提出過程改進計劃 | 20 | 20 |
合計 | 725 | 965 |
3.解題思路
拿到這個題目後,我想到的解題思路是首先解決解數獨的部分,生成數獨終局的時候就可以先隨機生成數獨殘局,再利用解數獨的方法把殘局變為終局。
解數獨這個部分我的思路是先把可以確定唯一答案的空格填好,找不到這樣的空格的時候,就找一個只有兩個候選數的空格進行嘗試。不斷重復這兩個過程,最終就可以把數獨解出來。
生成數獨時我的方法是先往固定的幾個格子裏隨機填寫數字,形成一個數獨殘局,再用解數獨的方法進行求解,生成數獨終局。
4.設計實現過程
程序主要有以下這幾個類。
- table包含一個數獨表格的所有信息
- block是一個格子的數據
- row是一行的數據
- column是一列的數據
- area是一個九宮格的數據。
程序主要有一下幾個函數:
- fill函數:給某一格填上某數,並刷新當前數獨表格與之相關的所有數據。
- work1函數 :把一個數獨殘局中可以確定唯一答案的空格填好。
- solve函數:解一個數獨殘局。
- make1函數:生成一個數獨殘局。
- makemany函數:生成n個數獨終局。
5.程序性能
由於我的算法簡單粗暴,所以我找不到可以改進性能的地方。
下面是性能分析圖
可見程序中消耗最大的函數是getcount,這個函數的作用是更新數獨表格的候選數信息,每次填寫一個數字以後都會調用getcount函數。
6.代碼說明
1 int solve(table *table1) { 2 int point = 0; 3 //printtable(table1); 4 //printposs(table1); 5 getcount(table1); 6 //printcount(table1); 7 int exit = 0; 8 exit = work1(table1); 9 //printtable(table1); 10 //printposs(table1); 11 //printcount(table1); 12 check(table1); 13 tabletry[point] = *table1; 14 point++; 15 tabletry[point] = *fill(table1, tryi, tryn[0]); 16 point--; 17 tabletry[point] = *fill(&tabletry[point], tryi, tryn[1]); 18 point++; 19 if (exit == 0) { 20 while (1) { 21 //cout << "begin try" << tryi / 9 + 1 << "行" << tryi % 9 + 1 << "\n"; 22 error = work1(&tabletry[point]); 23 //printtable(&tabletry[point]); 24 //printposs(&tabletry[point]); 25 //printcount(&tabletry[point]); 26 if (error == -1) { 27 //cout << "try another"; 28 point--; 29 //cout << point << endl; 30 if (point < 0) { 31 //cout << "無解" << endl; 32 return -1; 33 } 34 } 35 else { 36 if (check(&tabletry[point]) == 1) { 37 //cout << "over" << endl; 38 //printtable(&tabletry[point]); 39 writetable(&tabletry[point]); 40 break; 41 } 42 else { 43 point++; 44 tabletry[point] = tabletry[point - 1]; 45 point++; 46 tabletry[point] = *fill(&tabletry[point - 2], tryi, tryn[0]); 47 point--; 48 tabletry[point] = *fill(&tabletry[point], tryi, tryn[1]); 49 point++; 50 } 51 } 52 } 53 } 54 else { 55 //cout << "無解" << endl; 56 return -1; 57 } 58 return 0; 59 }
solve函數先把數獨表格中可以確定唯一答案的空格填好,找不到這樣的空格的時候,就找一個只有兩個候選數的空格進行嘗試。不斷重復這兩個過程,直到解完數獨或確定數獨無解。
7.總結
生成數獨終局的部分我沒有使用任何現有的高效算法,而是自己寫了一個隨機填數再求解的算法,算法的性能非常差,也不能保證生成的數獨不會重復。
我自己測試的時候是生成10000個數獨要12.5秒,更多的我也沒敢試,我覺得生成1000000個大約要20分鐘吧。
個人項目