Github項目地址:https://github.com/huarangmeng/031702142
PSP表格如下:
PSP2.1 | Personal Software Process Stages | 預估耗時(分鍾) | 實際耗時(分鍾) |
---|---|---|---|
Planning | 計划 | 20 | 20 |
Estimate | 估計這個任務需要多少時間 | 20 | 20 |
Development | 開發 | 340 | 300 |
Analysis | 需求分析(包括學習新技術) | 40 | 60 |
Design Spec | 生成設計文檔 | 20 | 10 |
Design Review | 設計復審 | 10 | 10 |
Coding Standard | 代碼規范(為目前的開發制定合適的規范) | 10 | 5 |
Design | 具體設計 | 30 | 30 |
Coding | 具體編碼 | 160 | 120 |
Code Review | 代碼復審 | 30 | 45 |
Test | 測試(自我測試,修改代碼,提交修改) | 50 | 60 |
Reporting | 報告 | 30 | 30 |
Test Report | 測試報告 | 10 | 10 |
Size Measurement | 計算工作量 | 10 | 10 |
Postmortem & Process Improvement Plan | 事后總結,並提出改進計划 | 10 | 10 |
合計 | 390 | 350 |
思路歷程
- 之前沒有玩過數獨,只能查詢數獨的解法,看了一部分“唯一解”法,發現不太能理解,之后尋找到了回溯解法。
- 嘗試先對九階標准數獨進行求解,完成主體思路
- 對數獨數組matrix[][] 從左至右,從上至下依次遍歷,matrix[][]==0,代表可填寫部分
- 對可填寫部分,進行填數檢測 check(row,line,num) ,如果通過,則martrix[row][line]=num, 進入下一個位置 backTrace(row,line+1),最關鍵點,要將matrix[row][line]=0,恢復原狀,如果下一次填數失敗,要回溯重新試下一個數字
- check(row,line,num)函數,需要檢測當前行列宮均與Num不同,否則返回false
- 主體思路結束后,發現需要使用命令行輸入輸出文件,不會,嗯,就是不會。開始學,從JAVA輸入輸出文件開始還行,命令行參數獲取有點懵逼,靠着@衡與墨 助教在微信群里的代碼才運行了。
- 之后才對3-9階進行區分,唯一需要改動的地方就是check()函數
- 將3,5,7階分為一類,即只需要檢測行與列是否相同
- 4,9階分為一類,即行、列宮數均為sqrt(階)
- 6單獨,8單獨,需要檢測宮的方法與其他不同
函數關聯
代碼改進
原本代碼只針對存在解的數獨進行求解,不存在報錯機制。
改進增加這一部分,增加是否存在解判斷 flag ,flag初始化為false,若有解 flag =true.
代碼如下:
//Judging Solvability
if(flag) {
System.out.println("Success!!!!");
} else{
System.out.println("The test is insoluble!!!!!!");
printf();
}
代碼讀取文件部分:
File file = new File(inputFileName);
int x[][] = new int[9][9];
int row = 0;
int line = 0;
String str = "";
if(! file.exists()){
System.out.println("對不起,不包含指定路徑的文件");
}else{
try{
FileReader fr = new FileReader(file);
char[] data = new char[23];
int length = 0;
while((length = fr.read(data)) >0){
str = new String(data,0,length);
for(int j = 0; j < str.length(); j++){
if(str.charAt(j) >47 && str.charAt(j)<58){
char c = str.charAt(j);
x[row][line++] = Character.getNumericValue(c);
if(line == phraseWordNum){
//Line feed
row++;
line = 0;
}
}
if(row == phraseWordNum){
//A disk is well stored
Lib lib = new Lib(x,phraseWordNum,outputFileName);
lib.Initialization();
row = 0;
line = 0;
}
}
}
//Close the read stream
fr.close();
}catch (Exception e){
e.printStackTrace();
}
}
回溯解法主體:
public void backTrace(int i, int j){
//End of Arrival Output
if(i == (rank-1) && j == rank){
printf();
flag = true;
return;
}
//Arrive at the end of the column, wrap
if(j == rank){
i++;
j = 0;
}
//If the lattice is empty, the judgement is entered.
if(matrix[i][j] == 0){
for(int k = 1; k <= rank; k++){
//Check whether the requirements are met
if(check(i,j,k)){
//Give the value K to the lattice
matrix[i][j] = k;
backTrace(i,j+1);
//Initialize the lattice
matrix[i][j] = 0;
}
}
}else {
backTrace(i,j+1);
}
}
檢測所填數字合理性代碼:
private boolean check(int row, int line, int k){
//Query whether rows or columns have duplicate numbers
for(int i = 0 ;i < rank; i++){
if(matrix[row][i] == k || matrix[i][line] == k)
return false;
}
//Query if there are duplicate numbers in the Nine-palace grid
if(rank == 4 || rank == 9){
int gong = (int)sqrt(rank);
int _row = row / gong;
int _line = line / gong;
for(int i = 0; i < gong; i++){
for(int j = 0; j < gong ;j++){
if(matrix[_row*gong + i][_line*gong + j] == k)
return false;
}
}
}else if(rank == 6){
int _row = row / 2;
int _line = line / 3;
for(int i = 0; i < 2; i++){
for(int j = 0; j < 3 ;j++){
if(matrix[_row*2 + i][_line*3 + j] == k)
return false;
}
}
}else if(rank == 8){
int _row = row / 4;
int _line = line / 2;
for(int i = 0; i < 4; i++){
for(int j = 0; j < 2 ;j++){
if(matrix[_row*4 + i][_line*2 + j] == k)
return false;
}
}
}
return true;
}
單元測試樣例:
-
四階數獨
-
五階數獨
-
六階數獨
-
七階數獨
-
八階數獨
-
九階數獨
-
運行截圖
性能分析
byte[], String ,類運行的最多,遠大於其他,應該是參數輸入,文件讀取數字存為矩陣時使用過多
(JProfiler 不會用,參數看不太懂)
心路歷程與收獲
最開始心中完全對數獨的陌生,尋找了很多關於數獨解法的文章,看得頭疼。
最大的收獲應該是JAVA的文件輸入輸出,以及命令行運行JAVA項目吧,之前一直沒有機會嘗試過,這次終於接觸了。
github上傳代碼,自己之前就試過一次,失敗了,這次陰差陽錯成功了?