软件工程实践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,文件操作。以及一些项目管理与测试的知识。

posted on 2019-09-24 12:27  张九思  阅读(370)  评论(5编辑  收藏  举报

导航