ZOJ-1002

      虽然学习了数据结构,但总感觉学得很浅,浮于表面具体应用还是不太会,所以开始刷OJ了,希望能有点收获吧。在ZOJ上刷,1001没啥可说的,就决定从1002开始做起了。题目就不多说了,直接开始代码吧。

      这道题要求的数据量不是很大,所以直接穷举所有可能性应该也行得通,这里主要用了深度优先算法,(话说数据结构的时候都没想到这个算法这么有用,光学不实践是真的是掌握不了),基本思想就是可以把整个过程想成一个类似树的结构(个人看法:感觉这样比较好理解),图中的每个格子看作树的一个节点,从第一个格子开始深度搜索,16个节点全部搜索完后,回溯到该节点,如果该节点设了碉堡,则变为没设碉堡的情况,从另一种可能情况的分支开始新一轮搜索,以此穷尽所有可能的情况,搜索的过程中保存本轮搜索的碉堡数,各次比较后,取得最大值。

具体依代码讲解如下:

       先上main函数吧:

int main(void) {
	ios_base::sync_with_stdio(false);
	while (cin >> n && n) { //等价于读取n且判断n是否等于0,若为0则退出循环
		for (int i = 0; i < n; i++)
			cin >> Map[i];
		ans = 0;   //初始化碉堡数为0
		dfs(0, 0); //从第一个格子开启深度优先搜索
		cout << ans << endl; //递归搜索结束后,输出碉堡最多的个数
	}
	//system("pause");
	return 0;
}

        main函数没有啥太重要的,结合着注释看应该ok的

        然后就是最重要的核心代码dfs深度优先搜索代码,代码如下:

void dfs(int num, int ans_temp) { //深度优先搜索,用1个num就能实现对16个格的遍历搜索,行用除法得到,列用取模得到
	if (num == n * n) {
		ans = max(ans, ans_temp);
		return;
	}
	else {
		int x = num / n;  //得到行号
		int y = num % n;  //得到列号
		if (Map[x][y] == '.'&&judge(x, y)) {
			Map[x][y] = 'C'; //设置为碉堡
			dfs(num + 1, ans_temp + 1);//碉堡总数,格子数加1,深度优先搜索下一格子
			Map[x][y] = '.';//实现回溯,如果不在这里建碉堡的情况分支
		}
		//else
		dfs(num + 1, ans_temp);//遍历下一格子
	}
}

这里几个要点,列在下面:

1.关于judge函数,其功能就是判断当前的x,y格子能不能放碉堡,具体内容会在下面指出来;

2.关于行号,列号的判断是在别的文章里看到的,直接设置一个总数num,用除法得到当前行号,用取模运算得到当前列号,刚开使在dfs函数中我设置了三个参数,其中两个分别传递行和列,但后来感觉这种方法更好,减少了传递的参数,同时递归出口的判断更为简单;

3.开始时,倒数第四行用了if-else的结构,但发现结果出错,原因在于这里不应该是一个单纯的分支结构,因为当if中一轮搜索结束时,节点重新被赋值为“.”(不建立碉堡)后,还要开始新一轮的递归搜索,如果用了else则无法开始新的一轮搜索;

4,如果对dfs搜索或递归不太理解,建议在dfs函数处设置断点,进行逐语句的调试,看num值的变化过程,应该会有帮助。

      最后是judge函数的内容:

bool judge(int x, int y) {
	for (int i = x - 1; i >= 0; i--) {//对所在列判断,看是否合法可建立碉堡
		if (Map[i][y] == 'C')         //该列已有碉堡且没有墙间隔,改点不合法无法建碉堡
			return false;
		if (Map[i][y] == 'X')         //检测到墙,则不管该列前面有没有碉堡,都没有影响,列合法
			break;
	}
	for (int i = y - 1; i >= 0; i--) {//对所在行判断,看是否合法,思想类似列
		if (Map[x][i] == 'C')
			return false;
		if (Map[x][i] == 'X')
			break;
	}
	return true;

      这里有个小点,就是遍历时只对该格子前面的格子进行判断,因为按顺序进行深度搜索,该点之后的格子默认为还没有进行过搜索,不在考虑之列。

      ok,1002就这么搞定了,耶!!!!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值