Github : https://github.com/O-VIGIA/031702414ios
PSP2.1 | Personal Software Process Stages | 預估耗時(小時) | 實際耗時(小時) |
---|---|---|---|
Planning | 計劃 | 1h | 0.5h |
Estimate | 估計這個任務須要多少時間 | 25h | 26h |
Development | 開發 | 5h | 1h |
Analysis | 需求分析 (包括學習新技術) | 1h | 1h |
Design Spec | 生成設計文檔 | 1h | 1h |
Design Review | 設計複審 | 1h | 0.5h |
Coding Standard | 代碼規範 (爲目前的開發制定合適的規範) | 1h | 0.5h |
Design | 具體設計 | 1.5h | 0.5h |
Coding | 具體編碼 | 5h | 5h |
Code Review | 代碼複審 | 1h | 0.5h |
Test | 測試(自我測試,修改代碼,提交修改) | 1.5h | 1h |
Reporting | 報告 | 2.5h | 3h |
Test Repor | 測試報告 | 0.5h | 1h |
Size Measurement | 計算工做量 | 0.5h | 0.5h |
Postmortem & Process Improvement Plan | 過後總結, 並提出過程改進計劃 | 2.5h | 3h |
合計 | 25h | 19h |
做業發佈的次日纔看到居然又有做業了,而後就用手機打開博客看一下題目。大體掃了一眼發現是數獨的題目,而後就想到了本身以前作過的一道極其類似的深搜回溯OJ題目,感受常規思路應該不會太難打。果不其然,當天我就面向過程打了個深搜作出了簡單的九階數獨問題。思考後我發現原來麻煩的是文件讀寫和命令行傳參,和寫博客分析。而後就開始了。git
思考:最常規的數獨引擎填寫算法github
大體的思惟導圖以下
算法
Check函數用來判斷是否合法數組
1 行合法性app
2 列合法性函數
3 對於某些特殊階數獨的小宮格合法性性能
4 須要判斷小宮格合法性的數獨經過思考發現計算小宮格左上角座標的公式單元測試
n--格子編號 || level--數獨階數 || height--小宮格高度學習
width--小宮格寬度 || x--小宮格左上角橫座標 || y--小宮格左上角縱座標
x=n/level /height *height
y=n %level /width *width
DFS+回溯 用來填寫空白的數獨部分
1 對全部格子進行編號n 從0開始從左到右從上到下
2 以公式法計算每一個編號的所在列所在行 以及 所在小宮的左上角座標
3 遍歷編號 並對爲0的格子 嘗試填入數字1~9
4 經過Check函數判斷填入的數字是否合法 若是合法對編號n+1繼續深搜下去 進行步驟三
5 不合法 退後一位 並將編號第n位的格子 還原爲0
代碼以下
/* Check函數:判斷key填入n時是否知足條件 */ /* ---Check Begin--- */ bool Check(int n,int key) { int x, y, height, width; for (int i=0;i<level;i++)// 判斷n所在橫列是否合法 { int j=n/level;// j爲n豎座標 if (num[j][i]==key) return false; } for (int i=0;i<level;i++)//判斷n所在豎列是否合法 { int j=n%level;//j爲n橫座標 if (num[i][j]==key) return false; } /* 若爲9,8,6,4階數獨則判斷小宮格 */ if (level==9||level==8||level==6||level==4) { /* x爲n所在的小九宮格左頂點豎座標 */ /* y爲n所在的小九宮格左頂點橫座標 */ /* height爲小宮格高度 */ /* weidth爲小宮格寬度 */ switch (level) { case 9: { x = n / 9 / 3 * 3; y = n % 9 / 3 * 3; height = 3; width = 3; break; } case 8: { x = n / 8 / 4 * 4; y = n % 8 / 2 * 2; height = 4; width = 2; break; } case 6: { x = n / 6 / 2 * 2; y = n % 6 / 3 * 3; height = 2; width = 3; break; } case 4: { x = n / 4 / 2 * 2; y = n % 4 / 2 * 2; height = 2; width = 2; break; } } for (int i=x;i<x+height;i++)//判斷n所在的小九宮格是否合法 { for (int j=y;j<y+width;j++) { if (num[i][j]==key) return false; } } } return true;//所有合法,返回正確 } /* ---Check End--- */ /* DFS函數 :深搜+回溯 解決數獨*/ /* ---DFS Begin--- */ int DFS(int n) { if (n>(level*level-1))//全部的都符合,退出遞歸 { sign = true; return 0; } if (num[n/level][n%level]!= 0) //當前位不爲空時跳過 { DFS(n+1); } else { for (int i=1;i<=level;i++)//不然對當前位進行枚舉測試 { if (Check(n,i)==true)//知足條件時填入數字 { num[n/level][n%level] = i; ``` DFS(n+1);//繼續搜索 if (sign==true) return 0;//返回時若是構形成功,則直接退出 num[n/level][n%level] = 0;//若是構造不成功,還原當前位 } } } ``` } /* ---DFS Begin--- */ /* init_num 函數:初始化num數組 */ /* ---init_num Begin--- */ void init_num() { for (int i = 0; i < 20; ++i) for (int j = 0; j < 20; ++j) num[i][j] = 0; } /* ---init_num end--- */
寫完了主要引擎,就考慮到了命令行傳參的問題,因而 百度。
百度以後發現原來
int main(int argc, char *argv[])
main函數裏面的參數原來是 則個意思
簡單來講 argc 就表明命令行參數的個數 argv[]數組裏面是命令行的參數內容(字符串類型)
而後我就開始了本身的思考:
咱們的標準命令行是長
Suduku.exe -m 8 -n 10000 -i input.txt -o ouput.txt
這樣用命令行傳參我須要 階數8 個數10000 讀入文件名input.txt 輸出文件名output.txt 這四個參數
測試後我發現 argv[0]是Suduku.exe
我想那麼以此類推 argv[2] argv[4] argv[6] argv[8] 不就正是我想要的參數
測試後果然如此
int main(int argc, char *argv[]) { /*從命令行接收參數 */ level = atoi(argv[2]); int m = atoi(argv[2]); int n = atoi(argv[4]); ``` /*對多個數獨進行操做*/ for(int kk=1;kk<=n;++kk){ sign=false; init_num(); sudu sudu1(m);//構造出m階數獨 sudu1.Martrix_input((int*)sudu1.Martrix, m, (char*)argv[6]);//從命令行指定的文件名中讀入一個m階數獨 sudu1.Martrix_num_sudu((int*)sudu1.Martrix, m);//數獨->數組 DFS(0); //數獨數組計算引擎 sudu1.Martrix_sudu_num((int*)sudu1.Martrix,m);//數組->數獨 sudu1.Martrix_output((int*)sudu1.Martrix, m, (char*)argv[8]);//在命令行指定的文件名中輸出數獨的解 } ``` }
解決了命令行傳參問題,下面就是文件流操做。
百度了一下發現 C++ fstream 這個庫提供了簡便的文件流操做
例如:
ifstream infile; infile.open(filename); infile>>「software」; infile.close();
可是爲了讀入完一個數獨後 還須要讀入下一個數獨
通過極度瘋狂思考以後
我仍是去百度了,百度以後發現了tellg()和seekg()這兩個文件指針操做
簡單來講tellg()就是把讀完一個數獨後的位置傳出來
seekg(offset,ios::beg)就是從你指定的地方偏移offset位 當前位ios::cur 起始位ios::beg 末位ios::end
(這個東西我嘗試了很久,好多坑 大坑就是打開文件要用二進制 不如可能會出現一點偏移問題)
我開始了本身的思考:
若是我把先把offset初始化爲0
每一次讀完數獨後的位置用tellg()傳出來賦值給offset而後從起始位偏移offset讀文件 天命hhhh
寫入就簡單多了直接用附加寫的方式 能夠在指定文件名後面附加寫入下一個數獨的解
outfile.open(filename,ios::app);//之後繼方式打開文件以便繼續寫
這時我突然須要創建起本身的數獨類 由於接受完參數和數據 我就能初始化類了
而後就開始了
不知道爲何我會把這個命令爲term
反正就開始了他就長這樣(某種緣由不能全發代碼)
class sudu { public: int row;//row=col行列相等 int *Martrix = new int[row*row];//建立時new一個數組 void Martrix_input(int *Martrix,int row,const char* filename); void Martrix_output(int *Martrix,int row,const char* filename); void Martrix_sudu_num(int *Martrix,int row); void Martrix_num_sudu(int *Martrix,int row); sudu(int a); ~sudu(); };
思想:
sudu(int a) 用level->a來構造一個level階的數獨
*Martrix 用來存放從文件中讀出的一個數獨數據 在析構函數~sudu()裏delete[]掉
Martrix_input 從文件中讀取一個等級位level的數獨數據
Martrix_output 向文件中寫入通過引擎後數獨的解
Martrix_sudu_num 鹹魚函數一號 將構造好的數獨數據從Martrix傳入num 以便本豆芽菜解決問題
Martrix_num_sudu 鹹魚函數二號 將num中已經解決完的數獨數據傳入Martrix 以便調用類輸出文件函數
理順cpp和.h的互相調用,也就是
stdafx.cpp stdafx.h Sudoku.cpp
這三個東西的關係
stdafx.h是用來定義各類資源
stdafx.cpp用來實現stdafx.h中的資源
Sudoku.cpp就跟引用庫函數同樣引用stdafx.h中的各類資源
而後提交到Git的時候注意建一個 .gitignore 文件用來忽略上傳的其餘文件
編譯時發現 DFS函數不是全部控件都有返回值 問題
解決問題後:
先上大的:
未測先飄
不知道是哪一個就兩個一塊兒
芬蘭數學家因卡拉,花費3個月時間設計出了世界上迄今難度最大的數獨遊戲,並且它只有一個答案。因卡拉說只有思考能力最快、頭腦最聰明的人才能破解這個遊戲。這是英國《每日郵報》2012年6月30日的一篇報道。
8 0 0 0 0 0 0 0 0 0 0 3 6 0 0 0 0 0 0 7 0 0 9 0 2 0 0 0 5 0 0 0 7 0 0 0 0 0 0 0 4 5 7 0 0 0 0 0 1 0 0 0 3 0 0 0 1 0 0 0 0 6 8 0 0 8 5 0 0 0 1 0 0 9 0 0 0 0 4 0 0 0 0 5 3 0 0 0 0 0 8 0 0 0 0 0 0 2 0 0 7 0 0 1 0 5 0 0 4 0 0 0 0 5 3 0 0 0 1 0 0 7 0 0 0 6 0 0 3 2 0 0 0 8 0 0 6 0 5 0 0 0 0 9 0 0 4 0 0 0 0 3 0 0 0 0 0 0 9 7 0 0
9階答案 傳說級因卡因之問1: 8 1 2 7 5 3 6 4 9 9 4 3 6 8 2 1 7 5 6 7 5 4 9 1 2 8 3 1 5 4 2 3 7 8 9 6 3 6 9 8 4 5 7 2 1 2 8 7 1 6 9 5 3 4 5 2 1 9 7 4 3 6 8 4 3 8 5 2 6 9 1 7 7 9 6 3 1 8 4 5 2 傳說級因卡因之問2: 1 4 5 3 2 7 6 9 8 8 3 9 6 5 4 1 2 7 6 7 2 9 1 8 5 4 3 4 9 6 1 8 5 3 7 2 2 1 8 4 7 3 9 5 6 7 5 3 2 9 6 4 8 1 3 6 7 5 4 2 8 1 9 9 8 4 7 6 1 2 3 5 5 2 1 8 3 9 7 6 4
原題及答案見博客做業
0 8 0 7 5 2 0 0 0 0 4 0 0 0 0 0 0 3 0 0 0 6 0 0 5 2 0 0 0 0 0 1 0 0 0 0 0 0 6 0 0 0 0 0 0 0 5 2 0 4 6 0 0 8 0 0 0 0 3 0 0 1 8 0 0 4 0 0 0 3 0 0 0 3 0 8 6 0 0 0 0 0 0 0 0 0 0 2 0 0 1 0 7 0 0 5 0 0 0 0 0 1 0 0 1 0 5 2 0 0 7 3 0 6 0 3 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 8 0 0 0 6 3 0 8 0 0 4 0 0 5 1 0 0 0 0 6 0 0 0 0 0 3 3 0 0 0 2 5 0 0 0 0 0 7 6 0 0 5 0 0 0 1 0 0 7 0
8階答案 初級: 4 8 1 7 5 2 3 6 1 6 4 3 8 7 2 5 7 3 5 2 1 6 4 8 5 2 8 6 4 3 7 1 8 7 2 1 3 5 6 4 3 1 7 8 6 4 5 2 2 4 6 5 7 8 1 3 6 5 3 4 2 1 8 7 高級: 6 4 2 5 1 3 8 7 5 3 7 8 6 2 4 1 7 1 3 4 8 5 6 2 8 2 1 6 7 4 3 5 4 5 8 7 3 1 2 6 1 8 5 2 4 6 7 3 2 6 4 3 5 7 1 8 3 7 6 1 2 8 5 4 骨灰級: 5 3 1 8 7 2 6 4 6 2 7 4 5 3 8 1 7 1 6 3 4 8 5 2 4 8 2 5 1 6 3 7 1 6 5 2 8 7 4 3 3 7 4 6 2 5 1 8 8 4 3 7 6 1 2 5 2 5 8 1 3 4 7 6
0 0 0 2 3 0 0 0 0 0 0 0 2 0 0 0 0 4 0 0 1 0 0 0 0 5 0 0 1 3 0 0 3 0 6 0 0 0 4 0 0 0 0 0 2 0 6 0 5 0 0 3 0 0 0 0 0 0 0 4 0 3 0 0 0 0 0 6 0 0 0 1 5 0 0 0 2 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 4 0 0 6 4 0 0 0 1 0 0 0 2
6階答案: 1 6 4 2 3 5 3 2 5 6 4 1 2 3 6 1 5 4 5 4 1 3 2 6 6 5 2 4 1 3 4 1 3 5 6 2 6 5 4 1 2 3 3 1 2 4 6 5 5 4 6 3 2 1 1 2 3 6 5 4 2 3 1 5 4 6 4 6 5 2 3 1 5 6 4 3 2 1 1 3 2 5 6 4 6 4 1 2 5 3 2 5 3 1 6 4 3 2 6 4 1 5 4 1 5 6 3 2
0 0 0 0 0 2 0 3 0 0 0 0 1 0 4 0 4 0 0 0 0 0 2 0 0 0 0 1 0 1 0 0 1 0 0 0 4 0 1 0 0 0 0 0 0 0 0 2
4階答案: 3 1 2 4 4 2 1 3 2 4 3 1 1 3 4 2 4 2 1 3 1 3 2 4 2 4 3 1 3 1 4 2 1 3 2 4 4 2 1 2 2 4 3 1 3 1 4 2