軟件工程實踐2019第三次作業


代碼地址

GitHub:https://github.com/JiuSiZhang/021700827
9.25更新,修改傳參方式。

PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(小時) 實際耗時(小時)
Planning 計划 1h 0.5h
Estimate 估計這個任務需要多少時間 15h 12.5h
Development 開發 1h 1h
Analysis 需求分析 (包括學習新技術) 3h 2h
Design Spec 生成設計文檔 1h 0.5h
Design Review 設計復審 1h 0.5h
Coding Standard 代碼規范 (為目前的開發制定合適的規范) 1h 0.5h
Design 具體設計 1h 1h
Coding 具體編碼 1h 1h
Code Review 代碼復審 1h 1h
Test 測試(自我測試,修改代碼,提交修改) 1h 1h
Reporting 報告 1h 1h
Test Repor 測試報告 1h 1h
Size Measurement 計算工作量 0.5h 0.5h
Postmortem & Process Improvement Plan 事后總結, 並提出過程改進計划 0.5h 1h
合計 15h 12.5h

解題思路

這個題目其實很簡單,本質就是搜索+回溯,我們只要寫一個dfs函數和check函數就應該可以完成了,比較麻煩的可能是環境方面的設置和讀入,話不多說,先上代碼,然后一一解釋。

dfs函數

基本的dfs函數,判斷當前空有沒用被填過,如有,則繼續向下搜索,否則開始填數並進行驗證記得回溯。

void dfs(int x)//dfs函數 遞歸填數 
{
	if (flag)//如果已經完成 直接返回 
	{
		return;
	}
	if (x == m * m)//已經找完 
	{
		output();
		flag = 1;
		return;
	}
	int r = x / m;//行
	int c = x % m;//列
	if (!s[r][c])//沒填過就填這個空 
	{
		for (int i = 1; i <= m; i++)
		{
			if (check(x, i))
			{
				s[r][c] = i;
				dfs(x + 1);
				s[r][c] = 0;//回溯 
			}
		}
	}
	else//已經有數就跳過 
	{
		dfs(x + 1);
	}
}

check函數

這個函數的主要作用是check行和列是否合法,並判斷是否為4 6 8 9,因為它們需要驗證宮。

bool check(int x, int val)//第一個驗證函數 驗證行與列且 4 6 8 9時需要判斷宮 
{
	int r = x / m;
	int c = x % m;
	for (int i = 0; i<m; i++)//行 
	{
		if (s[r][i] == val)
		{
			return 0;
		}
	}
	for (int i = 0; i<m; i++)//列 
	{
		if (s[i][c] == val)
		{
			return 0;
		}
	}
	if (m == 4)//4*4
	{
		if (check2(x, 2, 2, val))
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
	else if (m == 6)//6*6
	{
		if (check2(x, 2, 3, val))
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
	else if (m == 8)//8*8
	{
		if (check2(x, 4, 2, val))
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
	else if (m == 9)//9*9
	{
		if (check2(x, 3, 3, val))
		{
			return 1;
		}
		else
		{
			return 0;
		}
	}
	return 1;
}

check2函數

這個函數。用來判斷小宮內是否合法。

bool check2(int x, int r, int c, int val)//第二個驗證函數 判斷宮 
{
	int a = x / m;
	int b = x % m;
	a = a / r * r;//行
	b = b / c * c;//列
	for (int i = a; i<a + r; i++)
	{
		for (int j = b; j<b + c; j++)
		{
			if (s[i][j] == val)
			{
				return 0;
			}
		}
	}
	return 1;
}

output函數

輸出函數,將結果輸出至文件,注意不一定忽略行末空格。

void output()//輸出函數 
{
	for (int i = 0; i<m; i++)
	{
		for (int j = 0; j<m; j++)
		{
			fprintf(fp2, "%d", s[i][j]);//輸出至文件
			if (j < m - 1)
			{
				fprintf(fp2, " ");
			}
			
		}
		fprintf(fp2, "\n");
	}
}

main函數

注意讀入方式,一開始不知道怎么通過命令行讀入參數,后來看了先寫的同學的博客的百度后才知道的。argv【2】,argv【4】,argv【6】,argv【8】分別對應m,n,輸入文件名,輸出文件名,然后我們定義兩個FILE變量,通過fopen打開文件,再用fscanf讀取數據。輸出到文件用fprintf函數。

int main(int argc, char *argv[])
{
	//std::ios::sync_with_stdio(false);
	//cin.tie(0);
	//m = atoi(argv[2]);//讀取參數
	//n = atoi(argv[4]);
	//char *inputname = argv[6];
	//char *outputname= argv[8];
	string a, b, c, d;
	a = "-m";
	b = "-n";
	c = "-i";
	d = "-o";
	fp1 = NULL;
	fp2 = NULL;
	for (int i = 1; i < argc; i++)
	{
		if (argv[i] == c)
		{
			fp1 = fopen(argv[++i], "r");//打開輸入文件
			if (fp1 == NULL)
			{
				return -1;
			}
			continue;
		}
		if (argv[i] == d)
		{
			fp2 = fopen(argv[++i], "w");//打開輸出文件,清空文件
			if (fp2 == NULL) //
			{
				return -1;
			}
			continue;
		}
		if (argv[i] == a)
		{
			m = argv[++i][0] - '0';
			continue;
		}
		if (argv[i] == b)
		{
			n = argv[++i][0] - '0';
			continue;
		}
	}
	
	while (n--)
	{
		mst(s, 0);//初始化 
		flag = 0;
		for (int i = 0; i<m; i++)//輸入 
		{
			for (int j = 0; j<m; j++)
			{
				fscanf(fp1, "%d", &s[i][j]);//文件讀入
			}
		}
		//fp2 = fopen(outputname, "a");//打開輸出文件
		dfs(0);	//開始填數 
		if (n > 0)
		{
			fprintf(fp2, "\n");//輸出至文件

		}
	}
	if (fp1 != NULL)
	{
		fclose(fp1);//關閉輸入文件
	}
	
	if (fp2 != NULL)
	{
		fclose(fp2);//關閉輸出文件
	}
	return 0;
}

難點

其實本次的編程並不難,難的應該是一系列沒有學過的操作,比如文件操作,vs工程操作,github操作,這些需要自己去網上找資料學習,不過一遍之后的確熟悉了很多。

Code Quality Analysis檢查結果

性能分析工具Studio Profiling Tools分析結果

測試結果展示

3*3

4*4

5*5

6*6

7*7

8*8

9*9

全家福

收獲與心路歷程

學到很多東西,以前自己只會打打題目,其他東西都不怎么忙會用,通過這次實驗,學到了很多東西,github,vs,文件操作。以及一些項目管理與測試的知識。


免責聲明!

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



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