1. 程式人生 > >軟工實踐第二次作業

軟工實踐第二次作業

es2017 port 提交 回溯法 rep dfs 推薦 置換 cnblogs

Github:https://github.com/031502216/softWare

作業地址:http://www.cnblogs.com/easteast/p/7469291.html

PSP 2.1表格

PSP2.1Personal 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深度優先算法還有一個博客推薦的算法跳轉鏈接也可以嘗試,都比目前的方法更加優化。在本次的作業中,確實發現自身有很多不足的地方,包括對學術鉆研的心態和能力,這是以後要努力的地方。

軟工實踐第二次作業