1. 程式人生 > >個人項目

個人項目

planning write 調用 也不能 分鐘 tag 最終 dev 更新

個人項目博客

1.github項目地址
https://github.com/zhaobs-yu/sudoku


2.PSP表格

PSP2.1Personal Software Process Stages預估耗時(分鐘)實際耗時(分鐘)
Planning 計劃 5 5
· Estimate · 估計這個任務需要多少時間 5 5
Development 開發 670 910
· Analysis · 需求分析 (包括學習新技術) 120 240
· Design Spec · 生成設計文檔 5 5
· Design Review · 設計復審 (和同事審核設計文檔) 2 2
· Coding Standard · 代碼規範 (為目前的開發制定合適的規範) 3 3
· Design · 具體設計 60 120
· Coding · 具體編碼 300 360
· Code Review · 代碼復審 60 60
· Test · 測試(自我測試,修改代碼,提交修改) 120 120
Reporting 報告 55 55
· Test Report · 測試報告 30 30
· Size Measurement · 計算工作量 5 5
· Postmortem & Process Improvement Plan · 事後總結, 並提出過程改進計劃 20 20
合計 725 965

3.解題思路

拿到這個題目後,我想到的解題思路是首先解決解數獨的部分,生成數獨終局的時候就可以先隨機生成數獨殘局,再利用解數獨的方法把殘局變為終局。
解數獨這個部分我的思路是先把可以確定唯一答案的空格填好,找不到這樣的空格的時候,就找一個只有兩個候選數的空格進行嘗試。不斷重復這兩個過程,最終就可以把數獨解出來。
生成數獨時我的方法是先往固定的幾個格子裏隨機填寫數字,形成一個數獨殘局,再用解數獨的方法進行求解,生成數獨終局。


4.設計實現過程

程序主要有以下這幾個類。

  • table包含一個數獨表格的所有信息
  • block是一個格子的數據
  • row是一行的數據
  • column是一列的數據
  • area是一個九宮格的數據。

程序主要有一下幾個函數:

  • fill函數:給某一格填上某數,並刷新當前數獨表格與之相關的所有數據。
  • work1函數 :把一個數獨殘局中可以確定唯一答案的空格填好。
  • solve函數:解一個數獨殘局。
  • make1函數:生成一個數獨殘局。
  • makemany函數:生成n個數獨終局。

5.程序性能

由於我的算法簡單粗暴,所以我找不到可以改進性能的地方。
下面是性能分析圖

技術分享

技術分享

可見程序中消耗最大的函數是getcount,這個函數的作用是更新數獨表格的候選數信息,每次填寫一個數字以後都會調用getcount函數。


6.代碼說明

 1 int solve(table *table1) {
 2     int point = 0;
 3     //printtable(table1);
 4     //printposs(table1);
 5     getcount(table1);
 6     //printcount(table1);
 7     int exit = 0;
 8     exit = work1(table1);
 9     //printtable(table1);
10     //printposs(table1);
11     //printcount(table1);
12     check(table1);
13     tabletry[point] = *table1;
14     point++;
15     tabletry[point] = *fill(table1, tryi, tryn[0]);
16     point--;
17     tabletry[point] = *fill(&tabletry[point], tryi, tryn[1]);
18     point++;
19     if (exit == 0) {
20         while (1) {
21             //cout << "begin try" << tryi / 9 + 1 << "行" << tryi % 9 + 1 << "\n";
22             error = work1(&tabletry[point]);
23             //printtable(&tabletry[point]);
24             //printposs(&tabletry[point]);
25             //printcount(&tabletry[point]);
26             if (error == -1) {
27                 //cout << "try another";
28                 point--;
29                 //cout << point << endl;
30                 if (point < 0) {
31                     //cout << "無解" << endl;
32                     return -1;
33                 }
34             }
35             else {
36                 if (check(&tabletry[point]) == 1) {
37                     //cout << "over" << endl;
38                     //printtable(&tabletry[point]);
39                     writetable(&tabletry[point]);
40                     break;
41                 }
42                 else {
43                     point++;
44                     tabletry[point] = tabletry[point - 1];
45                     point++;
46                     tabletry[point] = *fill(&tabletry[point - 2], tryi, tryn[0]);
47                     point--;
48                     tabletry[point] = *fill(&tabletry[point], tryi, tryn[1]);
49                     point++;
50                 }
51             }
52         }
53     }
54     else {
55         //cout << "無解" << endl;
56         return -1;
57     }
58     return 0;
59 }

solve函數先把數獨表格中可以確定唯一答案的空格填好,找不到這樣的空格的時候,就找一個只有兩個候選數的空格進行嘗試。不斷重復這兩個過程,直到解完數獨或確定數獨無解。


7.總結

生成數獨終局的部分我沒有使用任何現有的高效算法,而是自己寫了一個隨機填數再求解的算法,算法的性能非常差,也不能保證生成的數獨不會重復。

我自己測試的時候是生成10000個數獨要12.5秒,更多的我也沒敢試,我覺得生成1000000個大約要20分鐘吧。

個人項目