【2024.2.1练习】01迷宫

题目描述


题目思路

一开始想用动态规划,但是这道题没有明显的顺序性和递推关系可以找,起点也是自定义的,鉴于迷宫尺寸不大,考虑使用DFS或BFS。

在自己推算几遍后发现,假设可以在地图上畅通无阻,那么格子只有可能像棋盘一样排列:

01010
10101
01010
10101
01010

用理想的格子与实际输入的图进行对比,找出存在差异的格子,这些格子便是不能通行的。

然后再从起点开始进行DFS/BFS,搜索出总共能够通行的格子数。

此外还有一个重要的优化,由于输入的起点个数极大,为10^5,不可能每次输入起点都要重新进行一次搜索,因此对整个图的记忆化应该在输入起点之前就完成,这时输入起点坐标只需在直接给出二维数组中的对应结果即可。


我的代码

最开始我的dfs函数如下:

#include <iostream>
#include <algorithm>
using namespace std;
int map[1002][1002];
int ans[1002][1002];
int n;
int m;
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
int answer;

void dfs(int x, int y) {
	ans[x][y]++;
	answer++;
	for (int i = 0; i < 4; i++)
	{
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (ans[nx][ny] == 0 && map[x][y]==map[nx][ny]) {
			dfs(nx, ny);
		}
	}
	ans[x][y] = answer;
}
int main() {
	int i;
	int j;
	cin >> n >> m;
	//限定边界
	for (i = 0; i <= n+1; i++)
	{
		map[i][n+1] = 2;
		map[i][0] = 2;
		map[0][i] = 2;
		map[n+1][i] = 2;
	}
	//初始化地图
	for (i = 1; i <= n; i++)
	{
		for ( j = 1; j <= n; j++)
		{
			char x = '1';
			if ((i + j) % 2 == 0) {
				x = '0';
			}
			char y;
			cin >> y;
			if (x == y) {
				map[i][j] = 0;
			}
			else {
				map[i][j] = 1;
			}
		}
	}
	//初始化每个格子的答案
	for (int A = 0; A <= n + 1; A++)
	{
		for (int B = 0; B <= n + 1; B++)
		{
			ans[A][B] = 0;
		}
	}
	//深度优先搜索
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= n; j++) {
			if (ans[i][j] == 0) {
				answer = 0;
				dfs(i, j);
			}
		}
	}
	while (m--) {
		int x;
		int y;
		cin >> x >> y;
		cout << ans[x][y]<<endl;
	}
	return 0;
}

代码测试了很多次没问题,样例也过了,可测试点全错误。仔细一看,果然还是递归函数写得有问题:在递归之前计数,answer自增;递归结束之后获取最终信息answer,看似合理,实则只能给搜索起点及周围的方格正确赋值,一旦接近递归边界,有些分支无法赋到正确的值。

这也给我了一个启示:如果要在DFS中计算总搜索格数或次数(或由叶子结点向上传递信息),最终获得完整信息的只能是根结点。

修改后使用栈容器存储搜索过的方格坐标,一次DFS彻底完成后再将搜索过的方格统一赋值。

正确代码:

#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
stack<pair<int, int>> stk;
int map[1002][1002];
int ans[1002][1002];
int n;
int m;
int dx[4] = { 0,0,1,-1 };
int dy[4] = { 1,-1,0,0 };
int answer;

void dfs(int x, int y) {
	ans[x][y]++;
	answer++;
	//对组入栈
	pair<int, int> p(x, y);
	stk.push(p);
	for (int i = 0; i < 4; i++)
	{
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (ans[nx][ny] == 0 && map[x][y]==map[nx][ny]) {
			dfs(nx, ny);
		}
	}
	ans[x][y] = answer;
}
int main() {
	int i;
	int j;
	cin >> n >> m;
	//限定边界
	for (i = 0; i <= n+1; i++)
	{
		map[i][n+1] = 2;
		map[i][0] = 2;
		map[0][i] = 2;
		map[n+1][i] = 2;
	}
	//初始化地图
	for (i = 1; i <= n; i++)
	{
		for ( j = 1; j <= n; j++)
		{
			char x = '1';
			if ((i + j) % 2 == 0) {
				x = '0';
			}
			char y;
			cin >> y;
			if (x == y) {
				map[i][j] = 0;
			}
			else {
				map[i][j] = 1;
			}
		}
	}
	//初始化每个格子的答案
	for (int A = 0; A <= n + 1; A++)
	{
		for (int B = 0; B <= n + 1; B++)
		{
			ans[A][B] = 0;
		}
	}
	//深度优先搜索
	for (i = 1; i <= n; i++)
	{
		for (j = 1; j <= n; j++) {
			if (ans[i][j] == 0) {
				answer = 0;
				dfs(i, j);
				while (!stk.empty()) {
                    //储存过的坐标赋值并出栈
					ans[stk.top().first][stk.top().second] = answer;
					stk.pop();
				}
			}
		}
	}

	while (m--) {
		int x;
		int y;
		cin >> x >> y;
		cout << ans[x][y]<<endl;
	}
	return 0;
}

很有对于才学尚浅的我而言是一道很有营养的题目。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值