個人github項目連接:https://github.com/54zhazhahui/131700114css
實現一個命令行程序,不妨稱之爲Sudoku。git
數獨盤面是個九宮,每一宮又分爲九個小格。在這八十一格中給出必定的已知數字和解題條件,利用邏輯和推理,在其餘的空格上填入1-9的數字。使1-9每一個數字在每一行、每一列和每一宮中都只出現一次,因此又稱「九宮格」。github
如今咱們想一步一步來,完成從三宮格到九宮格的進階;完成三宮格和其餘博客任務,就算過了初級考覈,其餘的算升級。具體各階規則以下:函數
三宮格:盤面是33。使1-3每一個數字在每一行、每一列中都只出現一次,不考慮宮; 四宮格:盤面是22四個宮,每一宮又分爲22四個小格。使1-4每一個數字在每一行、每一列和每一宮中都只出現一次; 五宮格:盤面是55。使1-5每一個數字在每一行、每一列中都只出現一次,不考慮宮; 六宮格:盤面是23六個宮,每一宮又分爲32六個小格。使1-6每一個數字在每一行、每一列和每一宮中都只出現一次; 七宮格:盤面是77。使1-7每一個數字在每一行、每一列中都只出現一次,不考慮宮; 八宮格:盤面是42八個宮,每一宮又分爲24八個小格。使1-8每一個數字在每一行、每一列和每一宮中都只出現一次; 九宮格:盤面是33九個宮,每一宮又分爲3*3九個小格。使1-9每一個數字在每一行、每一列和每一宮中都只出現一次; 性能
<style type="text/css"> .tg {border-collapse:collapse;border-spacing:0;} .tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;} .tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;} .tg .tg-0pky{border-color:inherit;text-align:left;vertical-align:top} </style>學習
<table class="tg"> <tr> <th class="tg-0pky">PSP2.1</th> <th class="tg-0pky">Personal Software Process Stages</th> <th class="tg-0pky">預估耗時(分鐘)</th> <th class="tg-0pky">實際耗時(分鐘)</th> </tr> <tr> <td class="tg-0pky">Planning</td> <td class="tg-0pky">計劃</td> <td class="tg-0pky">10分鐘</td> <td class="tg-0pky">5分鐘</td> </tr> <tr> <td class="tg-0pky">Estimate</td> <td class="tg-0pky">估計這個任務須要多少時間</td> <td class="tg-0pky">36小時</td> <td class="tg-0pky">48小時</td> </tr> <tr> <td class="tg-0pky">Development</td> <td class="tg-0pky">開發</td> <td class="tg-0pky">4小時</td> <td class="tg-0pky">6小時</td> </tr> <tr> <td class="tg-0pky">Analysis</td> <td class="tg-0pky">需求分析 (包括學習新技術)</td> <td class="tg-0pky">2小時</td> <td class="tg-0pky">6小時</td> </tr> <tr> <td class="tg-0pky">Design Spec</td> <td class="tg-0pky">生成設計文檔</td> <td class="tg-0pky">2小時</td> <td class="tg-0pky">4小時</td> </tr> <tr> <td class="tg-0pky">Design Review</td> <td class="tg-0pky">設計複審</td> <td class="tg-0pky">2小時</td> <td class="tg-0pky">1小時</td> </tr> <tr> <td class="tg-0pky">Coding Standard</td> <td class="tg-0pky">代碼規範 (爲目前的開發制定合適的規範)</td> <td class="tg-0pky">1小時</td> <td class="tg-0pky">4小時</td> </tr> <tr> <td class="tg-0pky">Design</td> <td class="tg-0pky">具體設計</td> <td class="tg-0pky">1小時</td> <td class="tg-0pky">1小時</td> </tr> <tr> <td class="tg-0pky">Coding</td> <td class="tg-0pky">具體編碼</td> <td class="tg-0pky">2小時</td> <td class="tg-0pky">1小時</td> </tr> <tr> <td class="tg-0pky">Code Review</td> <td class="tg-0pky">代碼複審</td> <td class="tg-0pky">2小時</td> <td class="tg-0pky">30分鐘</td> </tr> <tr> <td class="tg-0pky">Test</td> <td class="tg-0pky">測試(自我測試,修改代碼,提交修改)</td> <td class="tg-0pky">2小時</td> <td class="tg-0pky">8小時</td> </tr> <tr> <td class="tg-0pky">Reporting</td> <td class="tg-0pky">報告</td> <td class="tg-0pky">1小時</td> <td class="tg-0pky">1小時</td> </tr> <tr> <td class="tg-0pky">Test Repor</td> <td class="tg-0pky">測試報告</td> <td class="tg-0pky">30分鐘</td> <td class="tg-0pky">10分鐘</td> </tr> <tr> <td class="tg-0pky">Size Measurement</td> <td class="tg-0pky">計算工做量</td> <td class="tg-0pky">10分鐘</td> <td class="tg-0pky">20分鐘</td> </tr> <tr> <td class="tg-0pky">Postmortem & Process Improvement Plan</td> <td class="tg-0pky">過後總結, 並提出過程改進計劃</td> <td class="tg-0pky">30分鐘</td> <td class="tg-0pky">45分鐘</td> </tr> <tr> <td class="tg-0pky">合計</td> <td class="tg-0pky"></td> <td class="tg-0pky">19.2小時</td> <td class="tg-0pky">33.2小時</td> </tr> </table> # 解題思路 看完題目要求以後,我就本身動手畫了了一個九宮格。在作題目的過程當中,我慢慢體會到解題的思路。基本上就是,排查一個空可能填的數,當只剩下一種可能的時候就能夠填了。可是有時候可能有兩種或者更多的可能值,這就須要咱們去試探了。由於題目比較簡單,思路也很快就出來了。用正常的搜索+遞歸,就能把題目要求的惟一解(標準)數獨算出來。比較難的就須要咱們去試探了。據說有道史上最難的數獨,只有最聰明的人才能解出來,但願個人程序能夠算出來。 # 源代碼 先看一下主函數吧。這個文件輸入輸出我整整搞了兩天,最後發現兩個問題。一個是vs2017創建項目的時候,應該選擇創建Windows控制檯應用程序。還有一個問題就是input.txt和output.txt寫成input.txt.txt和output.txt.txt。講真的,我自閉了,心態被搞崩了。看了好多資料,用了無數的方法都不行。最後能夠實現的那一刻,內心舒服了好多。 **主函數** ``` int main(int argc, char** argv) { int i, j; ifstream ifp; ofstream ofp; m = atoi(argv[2]);//宮階數 n = atoi(argv[4]);//盤面數 choosemn(); ifp.open(argv[6]); if (!ifp.is_open())//判斷文件是否成功打開 cout << "文件打開失敗" << endl; ofp.open(argv[8]); if (!ofp.is_open()) cout << "文件打開失敗" << endl; while (n > 0) { resetmay(); for (i = 0; i < m; i++)//輸入數獨盤面 { for (j = 0; j < m; j++) { ifp >> a[i][j].num; } } inputsign(); scansign();測試
for (i = 0; i < m; i++)//輸出解出的數獨 { for (j = 0; j < m; j++) { if (j < (m - 1)) ofp << a[i][j].num << " "; else ofp << a[i][j].num; } ofp << endl; } ofp << endl; n--; } return 0;
}ui
**結構體定義數據**
struct number //每一個數的結構體 sa { int sign;//定義一個標記,表示這個數還有幾種可能的取值 int maybe[9] = { 1,2,3,4,5,6,7,8,9 };//定義num的可能取值 int num;//定義num的肯定值 }a[9][9];編碼
### 核心代碼 核心代碼是兩個函數,一個**惟一值函數**,一個**排查函數**。 **惟一值函數**
void onlyone(int i, int j)//這個函數是把惟一解求出來; { for (int k = 0; k < line; k++) //惟一解在maybe裏面 { if (a[i][j].maybe[k] != 0) { a[i][j].num = a[i][j].maybe[k]; a[i][j].maybe[k] = 0; a[i][j].sign = 0; del(i, j); break; } } }spa
**排查函數**
void deletehl(int i, int j) { for (int k = 0; k < line; k++)//把同一行的sign減一,把maybe的可能取值變零 { if (a[i][k].maybe[a[i][j].num - 1] != 0)//若是不等0,說明還沒去掉這個可能; //等0的話,說明前面已經去掉了,sign不用再減一了; { a[i][k].maybe[a[i][j].num - 1] = 0; a[i][k].sign--; if (a[i][k].sign == 1) { onlyone(i, k); } }//把同一行的相同可能值刪掉
if (a[k][j].maybe[a[i][j].num - 1] != 0) { a[k][j].maybe[a[i][j].num - 1] = 0; a[k][j].sign--; if (a[k][j].sign == 1) { onlyone(k, j); } }//把同一列的相同可能值刪掉 }
}
void deletegong(int i, int j) { //宮的首地址計算 //x,y;這個宮的首個數的地址爲a[x][y] ; int x, y; x = (i / gongrow) * gongrow; y = (j / gongline) * gongline; for (int gi = 0; gi < gongrow; gi++) for (int gj = 0; gj < gongline; gj++)//把同一宮的sign減一,把maybe【num】的取值變零 { if (a[gi + x][gj + y].maybe[a[i][j].num - 1] != 0) { a[gi + x][gj + y].maybe[a[i][j].num - 1] = 0; a[gi + x][gj + y].sign--; if (a[gi + x][gj + y].sign == 1) { onlyone(gi + x, gj + y); } } } }
惟一值函數就是當一個空的可能性只有一種的時候,就能夠填入了。 排查函數就是把同一列或同一行或同一宮的,已存在的值的可能性排除掉。 ### 數據測試 下面是5和6宮格的數據測試結果   ### 性能分析    ###總結 此次做業花了我很長的時間,可是也是收穫滿滿。好比說學會了在github上傳代碼,還有vs2017的使用,還有文件輸入輸出!!!在寫做業的過程當中遇到了不少困難,不少bug,不少意想不到的問題,當是經過本身的努力,一步步攻克過來,最後成功解決。我以爲這個過程纔是最重要的,也是我此次最大的收穫。