數獨——分析、設計與測評


1、github地址:https://github.com/kinglc/sudoku1943

2、解題思路:項目包括 輸入與輸出(文件讀寫、命令行),生成不重復終局,解數獨三個部分。

  (1)輸入與輸出

      文件讀寫和命令行雖然都不熟,但稍微百度就完全可以解決。

  (2)生成不重復終局

      先隨便寫了一個數獨終局

      1 2 3  4 5 6  7 8 9

      4 5 6  7 8 9  1 2 3

      7 8 9  1 2 3  4 5 6

 

      2 3 4  5 6 7  8 9 1

      5 6 7  8 9 1  2 3 4  

      8 9 1  2 3 4  5 6 7

 

      3 4 5  6 7 8  9 1 2

      6 7 8  9 1 2  3 4 5

      9 1 2  3 4 5  6 7 8

      只需要生成一定數量的數獨終局從簡單的入手就好,上圖第一行是隨手寫,后8行都可以看做根據第一行左移得到,第一行全排列有8!=40320種,然后交換2-3(因為數據只要求1e6,可以不 考慮),4-6,7-9行,再乘3!×3!,結果略大於1e6。

  (3)解數獨

      本來試着看了一下dancing links算法,但十字鏈表似乎好麻煩的樣子,於是老老實實用dfs暴力寫完了。

3、代碼設計

  (1)函數功能

    int main(int ,char *) :獲取命令行參數,進入不同處理函數

    void createFinal():參數為-c時:生成終局存入數組,並調用output(int,int)函數

    void workout(int):參數為-s時:通過深搜得出終局,用check(int,int)函數判斷,並調用output(int,int)函數

    bool check(int,int):判斷在該處填的數字是否合理

    void output(int,int):根據參數所代表的輸出順序輸出終局

    

  (2)關鍵函數

    生成終局:

void createFinal()
{
    int tmp[9] = { 8,9,1,2,3,4,5,6,7 };//tmp表示第一行數字
    int i, j, k, moveleft[8] = { 3,6,1,4,7,2,5,8 };    //moveleft表示2-9行在第1行基礎上整體左移位數
    for (i = 0; i < 40320; i++)    //8!=40320
    {
        memcpy(numBoard[0], tmp, sizeof(tmp));
        //將第1行左移生成2-9行
        for (j = 0; j < 8; j++)
            for (k = 0; k < 9; k++)
                numBoard[j + 1][k] = numBoard[0][(k + moveleft[j]) % 9];//初始圖完成
        //調換4-6,7-9行
        for (j = 0; j < 6; j++)
            for (k = 0; k < 6; k++)
            {
                output(j, k);
                if (!--testnum)
                    return;
            }
        next_permutation(tmp + 1, tmp + 9);//重置第一行
    }
    return;
}
void createFinal()

 

    解數獨:

void workout(int pos)//深搜
{
    if (pos == 81)
    {
        output(0, 0);
        flag = 1;    //標記是否輸出過
        return;
    }
    int i, x, y;
    x = pos / 9;
    y = pos % 9;
    if (!numBoard[x][y])
    {
        for (i = 1; i <= 9; i++)
        {
            if (cnt[i - 1] == 9)
                continue;
            numBoard[x][y] = i;//填充數字
            cnt[i - 1]++;
            if (check(pos, i))
                workout(pos + 1);
            if (flag)    //該數獨已解完
                return;
            cnt[i - 1]--;
            numBoard[x][y] = 0;
        }
    }
    else
        workout(pos + 1);
}
void workout(int pos)

   (3)單元測試

 

       命令行參數判定:-c,  -s,  -abc

       運行情況判定:-c 1,  -c 1000,  -c  1000000,  -s 文件路徑(其中包含1、1000、1000000個用例)

4、運行分析

    (1)生成1000個數獨終局

  (2)解1000個20-40個空格的數獨

  (3)優化

    在生成終局中,本來是用了三次全排列分別對第一行8個數字、第4-6行、7-9行處理,后優化為用print[6][3]={ 0,1,2,0,2,1,1,2,0,1,0,2,2,1,0,2,0,1 }存入全排列數,在output函數中處理輸出。

void output(int mid,int last)
{
    int i, j, k, row;
    int order[3] = { 0 };
    order[1] = mid;
    order[2] = last;
    for (i = 0; i < 3; i++)//輸出第i個三行
        for (j = 0; j < 3; j++)
        {
            row = print[order[i]][j] + 3 * i;
            for (k = 0; k < 8; k++)
                output_file << numBoard[row][k] << " ";
            output_file << numBoard[row][8]<<endl;
        }
    output_file << endl;
}
void output(int mid,int last)

5、PSP

 PSP2.1  

   Personal Software Process Stages    

 預估耗時(分鍾)

 實際耗時(分鍾)

Planning

計划

30

30

·Estimate

·估計這個任務需要多少時間

30

30

Development

開發

1080

 1080

·Analysis

·需求分析(包括學習新技術)

120

120

·Design Spec

·生成設計文檔

120

90

·Design Review

·設計復審

30

30

·Coding Standard

·代碼規范

30

30

·Design

·具體設計

180

180

·Coding

·具體編碼

540

540

·Code Review

·代碼復審

30

30

·Test

·測試

30

60

Reporting

報告

 90

 90

·Test Report

·測試報告

40

40

·Size Measurement

·計算工作量

10

10

·Postmortem&Process Improvement Plan

·事后總結並提出過程改進計划

40

40

 

合計

1200

1200


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM