BUAA2017軟工 第1次個人專案 數獨

2022-07-16 17:51:16 字數 2665 閱讀 5983

在拿到這個題目時,我的第乙個想法是這樣的:9乘9的大方格有9個3乘3的小方格,在每個方格中隨機的寫入2到3個數,同時不違背數獨的規則,之後從第乙個空格開始,按照從左至右,從上至下的原則進行回溯,每次回溯所選取的值是在當前情況下,滿足數獨遊戲規則所能選取的值中的乙個,如果發現當前空格內沒有可選取的值,則證明至少上一步的選擇是錯誤的,回溯到上次選擇重新進行選取。這可能是邏輯上最簡單的演算法之一,但考慮到後續有對程式效能的考察,那麼這種暴力回溯演算法就放棄了。但是求解數獨時還是採用的這種方法。

暴力回溯不可取,於是自然而然的想到了按照某一種數學規則進行數獨的生成。請教了一位同學,將9個數字分為3組,比如147,258,369,之後在每個3乘3的方格中,將這9個數字分成3次填入,每次直接填1組的三個數字,下圖就是乙個例子:

後來在網上查資料時看到了一篇部落格,部落格中的演算法是對於乙個已知的數獨矩陣,將矩陣中的對映到中,並且保證對映後的數字與之前的數字存在不同,按照對映後的數字重新生成數獨,就會得到乙個與之前不同的數獨。這是演算法的基本原理,需要進一步改進後才可以適應我們的問題。

首先,需要解決對映問題。現有123456789這樣乙個序列,我們要將它不斷的加以變換,也就是要得到它的全排列。在大二學習的組合數學中,是有講過生成全排列(不斷得到下一字典序的序列)的演算法的,具體的演算法和**請看之後的**說明部分。

對映的問題解決了,之後我們要找到要施以變換的數獨,需要幾個數獨呢?乙個9個數字的序列的全排列一共可以產生9!個序列,但是,因為題目中有對數獨左上角第乙個數字的要求:

"在生成數獨矩陣時,左上角的第乙個數為:(學號後兩位相加)% 9 + 1。例如學生a學號後2位是80,則該數字為(8+0)% 9 + 1 = 9"

所以實際上是對8個數字全排列,得到的序列數是8!個,近40000,為滿足最後測試資料1000000的需求,我們要準備至少25個基礎數獨。

ans = ""

while (true):

s = input("please input string: ")

if len(s) == 3:

print(ans)

ans = ""

for i in s:

if i in ['1','2','3','4','5','6','7','8','9']:

ans += i

最後得到的效果是這樣的:

整體程式的實現過程是這樣的:

定義了乙個布林函式checksudoku(sudoku),用來檢測乙個9乘9的數字矩陣是否滿足數獨的遊戲規則,滿足則返回true,否則返回false

1.最開始的版本生成100萬個數獨的時間為73.43秒,之後通過visualstudio自帶的效能分析工具進行檢測,發現耗時最多的函式是fprintf

想到的優化方案是將要輸出的數字先都整合在乙個字串上,最後一次性輸出。優化後生成100萬個數獨的時間為38.67秒,提速了近50%。

2.將第一次優化後的版本再次使用效能分析工具進行分析,得到如下的結果。

發現佔93%時間的是c++裡string類中的字串拼接符號 += ,然而,我們需要每個數字之間都有空格,紅色最深的兩行已經不能再進行優化了。但是,如果我們使用字串陣列中對於單個字元的賦值符 = ,會提速不少。經過改進,生成100萬個數獨的時間只需要1.88秒,與之前的結果不在乙個數量級上。

最終的版本進行效能分析後,程式中消耗最大的函式是fputs。

3.呃,在debug環境生成的exe得到100萬個數獨需要1.88秒,而在release環境下得到100萬個數獨只需要0.88秒。

生成數獨功能最重要的部分是得到全排列,求解數獨功能關鍵的部分則是遞迴函式。

生成全排列:

/*得到全排列來進行數獨中數字的對映*/

void updatebasicsudokunum(int num)

}if (k == -1)

int min = 10;

int minnum = 0;

//a[k+1]到a[7]中,所有數字都比a[k]大,在其中找到最小的數字

for (int i = k + 1; i <= 7; i++)

}//將找到的這個最小的數字與a[k]進行交換

int tmp = basicsudokunum[num][minnum];

basicsudokunum[num][minnum] = basicsudokunum[num][k];

basicsudokunum[num][k] = tmp;

//之後將a[k+1]到a[7]的順序顛倒

for (int i = k + 1; i <= 7; i++) }}

回溯求解數獨:

/*回溯求解數獨*/

void solvepuzzle(int x, int y)

}//如果該位置最終選取的數字是0,則證明之前的某一步填錯了,需進行回溯

if (puzzle[i][j] == 0)

return;}}

//判斷數獨的所有位置是否都已經填滿

flag = true;

for (int i = 0; i < 9; i++)

}//判斷生成的數獨是否正確

if (!checksudoku(puzzle))

flag = false;

if (flag)

}

2017BUAA軟工 第3次個人作業

軟工第3次個人作業 案例分析 bug2 bug3 讓採訪物件使用10 30分鐘這個軟體的基本功能 請上傳 證明使用者的確正在使用,遠端採訪的同學請讓別人幫忙照相 描述使用者使用這個產品的過程,使用者的問題解決了麼?軟體在資料量 介面 功能 準確度上各有什麼優缺點?使用者體驗方面有問題麼?缺點使用者對...

2017BUAA軟工第0次作業

第一部分 結緣計算機 1.你為什麼選擇計算機專業?你認為你的條件如何?和這些博主比呢?我在上大學之前,其實一直就沒怎麼考慮過自己以後想要選什麼專業,只知道乙個大致的方向一定是理工科。畢竟大學之前,只有乙個目標,那就是高考嘛,高考之前,一切都是虛的。考完以後,面對自己不上不下的分數,照往年的資料胡亂圈...

軟工第1次個人作業

在中國,軟體工程師的考試有 計算機等級考試和全國計算機技術與軟體專業技術資格考試 也有這樣一些侷限性 以答題 評分為主要考試形式,沒有面對面的考試 乙個軟體工程師,對於他的能力應該如何量化地評定?我認為這些所謂的考級並不能評定軟體工程師的能力。現在網路上對於譚浩強的c語言教材可以說是頗多批判之聲,更...