軟工實踐第二次作業
Github:https://github.com/031502216/softWare
作業地址:http://www.cnblogs.com/easteast/p/7469291.html
PSP 2.1表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | -- | -- |
· Estimate | · 估計這個任務需要多少時間 | 15h | 20h |
Development | 開發 | -- | -- |
· Analysis | · 需求分析 (包括學習新技術) | 3h | 5h |
· Design Spec | · 生成設計文檔 | 30min | 30min |
· Design Review | · 設計復審 (和同事審核設計文檔) | -- | -- |
· Coding Standard | · 代碼規範 (為目前的開發制定合適的規範) | 10min | 10min |
· Design | · 具體設計 | 20min | 30min |
· Coding | · 具體編碼 | 5h | 8h |
· Code Review | · 代碼復審 | 2h | 2h |
· Test | · 測試(自我測試,修改代碼,提交修改) | 2h | 2h |
Reporting | 報告 | -- | -- |
· Test Report | · 測試報告 | 45min | 1h |
· Size Measurement | · 計算工作量 | 15min | 30min |
· Postmortem & Process Improvement Plan | · 事後總結, 並提出過程改進計劃 | 30min | 1h |
合計 | 13h30min | 20h40min |
學習進度條:
時間 |
新增代碼(行) |
本周學習耗時(小時) |
累計學習耗時(小時) |
重要成長 |
2017.9.3-2017-9.10 |
200 | 20 | 20 | 對回溯法有了更深的認識,C++挺久沒有接觸了,這一次寫的有些吃力,還有一些以前沒有接觸過的工具要一步步調試,覺得挺有收獲,不過看著自己和有些人在編程這方面確實存在很大差距,所以接下來要加把勁了。 |
... |
解題思路:
由於許久沒有寫過c++,所以感覺很多之前學的知識都已經沒有什麽印象,只能一點點回憶,慢慢完成本次作業,。在拿到題目後,自己先動手解了一下數獨,發現解是可以解出來,但是沒有找到特別的好技巧,只能慢慢推理。然後查詢了一些專門的解數獨教程,方法也是多種多樣,但是能夠提供解決問題算法的沒有太多,後來參考部分的網上資料,大致提供了兩種解決方法,分別是回溯和置換。置換法對於本題不太合適,那就使用回溯法。從問題的某一種狀態(初始狀態)出發,搜索從這種狀態出發所能達到的所有“狀態”,當一條路走到“盡頭”的時候(不能再前進),再後退一步或若幹步,從另一種可能“狀態”出發,繼續搜索,直到所有的“路徑”(狀態)都試探過。這種不斷“前進”、不斷“回溯”尋找解的方法,就稱作“回溯法”。但是在回溯的過程中怎麽樣才能將所有符合條件的數獨全部輸出呢?數獨一般都是提供幾個數字,然後根據規則填入相應的格子,但是本題是固定了左上角的數字,然後輸出滿足條件的數獨,並非解數獨那種單一的解法結構。但是相同的是需要用同一種規則去判斷,生成的結果是一個81格的數獨。
實現的時候有幾個問題:
1.不能生成相同的數獨,那麽在生成第一個數獨以後怎麽把第二個數獨輸出?
2.一個個的按順序往格子裏填寫數字,是不是對於性能方面有許多限制,浪費很多時間。
3.看到一些人在使用的時候使用了rand()這種隨機函數,這種方法是否對於生成數獨性能上和唯一性上有較大的提升?
綜合這些問題,再去尋找答案,心裏對於回溯這個方法還是比較認可,也是一個效率相對較高的方法。
設計實現:
代碼中有兩個函數,back()回溯函數和Isvaild()判斷放置數字是否合法。
工作流程圖:
代碼說明:
bool Isvaild(int count) //判斷是否合法 { int row = count / 9; int col = count % 9; int j; //同一行 for(j = 0; j < 9; ++j){ if(map[row][j] == map[row][col] && j != col){ return false; } } //同一列 for(j = 0; j < 9; ++j){ if(map[j][col] == map[row][col] && j != row){ return false; } } //九宮格 int Row = row / 3 * 3; int Col = col / 3 * 3; for(j = Row; j < Row + 3;++j){ for(int k = Col; k < Col + 3; ++k){ if(map[j][k] == map[row][col] && j != row && k != col){ return false; } } } return true; }
void back(int k,int request){ //進行回溯 while(1) { int i = k/9; int j = k%9; while(1) { map[i][j]++; if(map[i][j] == 10) { map[i][j] = 0; --k; break; } else if(Isvaild(k)) { ++k; break; } } if(k == 81) { for(int i = 0; i < 9; ++i){ for(int j = 0; j < 9; ++j){ fout<<map[i][j]<<" "; //cout<<map[i][j]<<" "; } fout<<endl; //cout<<endl; } num++; fout<<endl; //cout<<endl; if(num >= request) return; --k; } }
測試運行:
測試運行:
n=1000時
由上述截圖可以看出back()回溯函數占用了75%的時間,所占用的比例較重。
在本次作業實現過程中,我是發覺了自己的程序其實是有很大的優化空間的,但是由於時間和能力限制,並沒有去實現,但是接下來會去嘗試。以下提供一個解決問題的更好的思路可以減少回溯的次數例如dfs深度優先算法還有一個博客推薦的算法跳轉鏈接也可以嘗試,都比目前的方法更加優化。在本次的作業中,確實發現自身有很多不足的地方,包括對學術鉆研的心態和能力,這是以後要努力的地方。
軟工實踐第二次作業