軟件工程實踐2019秋第三次做業

第一次我的編程做業

Github倉庫地址https://github.com/JoekrLSJ/031702444node

1.PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃 60 30
Estimate 估計這個任務須要多少時間 1440 1200
Development 開發 180 240
Analysis 需求分析 (包括學習新技術) 60 120
Design Spec 生成設計文檔 60 30
Design Review 設計複審 120 60
Coding Standard 代碼規範 (爲目前的開發制定合適的規範) 120 60
Design 具體設計 60 60
Coding 具體編碼 120 180
Code Review 代碼複審 120 60
Test 測試(自我測試,修改代碼,提交修改) 120 120
Reporting 報告 60 30
Test Repor 測試報告 120 150
Size Measurement 計算工做量 60 30
Postmortem & Process Improvement Plan 過後總結, 並提出過程改進計劃 180 150
合計 1440 1200

2.解題過程

(1)解題思路

​ 讀完題目,第一個想法就是DFS+回溯,總結了一下宮格的特徵,發現能夠分紅兩類,一類是有宮的(四六八九宮格),一類是無宮的,即只要判斷行列是否衝突(三五七宮格)。題目說是惟一解,因此每次只要填入的是沒有衝突的數字,最後能所有填完,就是答案。git

(2)程序設計流程圖

(3)代碼實現

Soduku.cpp 1.0github

要點說明編程

這是最初的版本,先從簡單的三五七宮格入手,只要設置行列標記,位置不衝突便可填入,填不完回溯,最後填完就是答案。
設置標記函數

int  Soduku_map_row[maxn][maxn];                                //行標記,未填入爲0
int  Soduku_map_column[maxn][maxn];                             //列標記,未填入爲0
int  flag;                                                      //填完標記

用結構體隊列存儲待填格子行列位置工具

struct node
{
    int nrow;
    int ncolumn;
} blank_node[maxn*maxn],pos_node[maxn];                         //記錄未填入宮格的行列座標

求解方法:DFS+回溯函數post

Soduku_find()性能

調用這個函數計算三五七宮格數獨單元測試

void Soduku_find(int now)
{
    if (flag) return;
    if (now == blank_node_count + 1)
    {
        flag = 1;
        return;
    }
    int x = blank_node[now].nrow;
    int y = blank_node[now].ncolumn;
    rep(i, 1, n)
    {
        if ((!Soduku_map_row[x][i]) && (!Soduku_map_column[y][i]))
        {
            Soduku_map_row[x][i] = 1;                   //行不衝突
            Soduku_map_column[y][i] = 1;                //列不衝突
            Soduku_map[x][y] = i;                       //這個格子填入i
            Soduku_find1(now + 1);                      //填下一個格子
            if (flag) return;                           //填完退出
            Soduku_map_row[x][i] = 0;                   //行標記
            Soduku_map_column[y][i] = 0;                //列標記
        }
    }
}

輸入函數 Soduku_input()學習

void Soduku_input()
{
    rep(i, 1, n)
    {
        rep(j, 1, n)
        {
            cin >> Soduku_map[i][j];
            if (Soduku_map[i][j] == 0)
            {
                blank_node_count++;
                blank_node[blank_node_count].nrow = i;
                blank_node[blank_node_count].ncolumn = j;
            }
            else
            {
                Soduku_map_row[i][Soduku_map[i][j]] = 1;
                Soduku_map_column[j][Soduku_map[i][j]] = 1;
                if (!(n == 3 || n == 5 || n == 7))
                {
                    int pos = getpostion(i, j, pos_node[n].nrow, pos_node[n].ncolumn, n);
                    Soduku_positon[pos][Soduku_map[i][j]] = 1;
                }
            }
        }
    }
}

輸出函數 Soduku_outputput()

void Soduku_output()
{
    rep(i, 1, n)
    {
        rep(j, 1, n)
        {
            if (j != n)cout << Soduku_map[i][j] << " ";
            else cout << Soduku_map[i][j];
        }
        cout << endl;
    }
    cout << endl;
}

Soduku.cpp 2.0

因爲四六八九宮格每種宮格的行列劃分的方法不同,因此設計了一個函數輸入待填位置的行列座標和小宮格行列數以及大宮格的邊長就能算出當前位置在哪一個宮格。

宮格函數int getpostion(int,int,int,int,int)

int getpostion(int x, int y, int row, int column, int n)
{
    return (x - 1) / row * (n / column) + (y - 1) / column + 1;
}

舉個例子,在九宮格(5,4)位於第5宮格,(5 - 1)/ 3 *(9 / 3)+ (4 -1)/ 3 +1=5。每一個宮格3行3列,(x - 1)/ row算出在第幾行的宮格,乘上每行有(n / cloumn)個宮格,再加上在第幾列的宮格上(y - 1) / column + 1,最後就是所在宮格的位置。

加入宮標記

Soduku_positon[maxn][maxn];                                 //宮標記,未填入爲0

增長void Soduku_find2(int)函數,計算四六八九宮格數獨。

void Soduku_find2(int now)
{
    if (flag) return;
    if (now == blank_node_count + 1)
    {
        flag = 1;
        return;
    }
    int x = blank_node[now].nrow;
    int y = blank_node[now].ncolumn;
    int pos = getpostion(x, y, pos_node[n].nrow, pos_node[n].ncolumn, n);
    rep(i, 1, n)
    {
        if ((!Soduku_map_row[x][i]) && (!Soduku_map_column[y][i]) && (!Soduku_positon[pos][i]))
        {
            Soduku_map_row[x][i] = 1;                   //行不衝突
            Soduku_map_column[y][i] = 1;                //列不衝突
            Soduku_positon[pos][i] = 1;                 //宮不衝突
            Soduku_map[x][y] = i;                       //這個格子填入i
            Soduku_find2(now + 1);                      //填下一個格子
            if (flag) return;                           //填完退出
            Soduku_map_row[x][i] = 0;                   //行標記
            Soduku_map_column[y][i] = 0;                //列標記
            Soduku_positon[pos][i] = 0;                 //宮標記
        }
    }
}

(4)單元測試樣例

三宮格

四宮格

五宮格

六宮格

七宮格

八宮格

九宮格

後面簡單寫了個批處理文件test.bat測試一下輸出結果的正確性。

test.bat代碼

@echo off
title "Black Box Test"
for %%i in (3,4,5,6,7,8) do
 (
echo 當前測試第m%%in5組:
echo 5 %%i > input.txt
type m%%in5.txt >> input.txt
Sudoku
fc output.txt m%%in5_answer.txt /W
pause >nul
del input.txt
del output.txt
)

若是輸入文件output.txt和m3n5answer.txt內容一致答案正確就會顯示「找不到相異處」,反之會提示兩個文件不同的地方。

(5)異常處理

在編譯的時候一直出現C4996的錯誤沒法消除,查了一下是由於freopen和預處理器的問題,經過在預處理器最上方,也就是第一行添加以下代碼,便可解決該錯誤:

#pragma warning(disable:4996)

(6)性能分析

3.回顧總結

​此次題目難度不是很難,主要的時間都花在了熟悉VS 2017的使用,學習如何建立項目,初步學習使用性能分析工具,如今還不是很熟練,後面要熟練掌握。此次還學習了PSP流程,順便複習了一下int main(int argc,int *argv[])的使用方法。最後熟悉了在Github上面管理代碼的方法和流程。

相關文章
相關標籤/搜索