POJ - 3984 5x5迷宫(预处理、DFS回溯) 难度:算法入门 复杂度:比较复杂 (待模板化)...

很简单的一道迷宫题,我说的简单是指..地图大小 因为是固定5x5的点阵迷宫,且保证有唯一解,算是迷宫入门题吧 不过本人作为ACM小白头一次摸出这题还真是不容易啊

预处理:

就是给地图的四周“造墙”,比如把 变成 这样后面搜索时对待边界或障碍物就能共用一套逻辑, 因此5x5的地图要用7x7的数组来存储

然后就是模拟了:(貌似也可以叫做回溯?) 本人代码的大致逻辑是, 用每行3个数字的无限行数组road[][3]存储路径,前两个数字表示坐标,第三个数字表示这个坐标的“岔路口数”, (“岔路口数”是我自己起的名,表示这个点的上下左右有几个方向是可以走的,如果“岔路口数”等于2,那就是一条路的中间,如果等于1,那就是个死胡同)

我用一个整型变量direction对4取模后的值表示方向,换向逻辑是: 前方是墙时就都往右下角转向,表现为direction的值加1或减1,转向之后重复判断,如果还是不能走则重复转向,转到能走为止, 特殊地,如果右方下方都是墙,才往反方向换方向(为了避免搜索点在一个环形道绕圈)

从左上角开始往下或右走,每走出一步,在road[][3]记录当前坐标点和当前点的“岔路口数”, 若“岔路口数”等于1,说明走到了死胡同, 这时候将搜索点重置为road[][3]里上一个“岔路口数”>=3的点(我管这叫传送), 顺便将road[][3]中这个重置点的下一步所在坐标点“造个墙”,即把地图中对应点改为墙,封死死路入口, (传送之后,road数组里还留有之前行走路径,因此可得知死胡同的入口点) 之后的行走轨迹从重置点的位置开始往下覆盖, 重复以上步骤走到终点坐标为止,然后按格式输出road数组里的行走轨迹即可(逗号后面跟了一个空格)

因为在写这道题时本人还不懂DFS之类的东西,摸出来的解题逻辑和代码可能有偏复杂的地方,模板化解法回头再补充

#include<iostream>
using namespace std;
int main()
{
	int maze[7][7][2] = { 0 };
	for (int i = 0; i < 7; i++)
	{
		maze[0][i][0] = 1;
		maze[i][0][0] = 1;
		maze[6][i][0] = 1;
		maze[i][6][0] = 1;
	}
	for (int down = 1; down < 6; down++)
	{
		for (int right = 1; right < 6; right++)
		{
			cin >> maze[down][right][0];
		}
	}
	int road[3][100] = { 0 };
	int down = 1, right = 1;
	int direction = 4000;//0-up 1-left 2-down 3-right
	int iroad = 0;
	while (down != 5 || right != 5)
	{
		iroad++;
		road[0][iroad] = down;
		road[1][iroad] = right;
		road[2][iroad] = 0;
		if (maze[down - 1][right][0] != 1)
			road[2][iroad]++;
		if (maze[down][right - 1][0] != 1)
			road[2][iroad]++;
		if (maze[down + 1][right][0] != 1)
			road[2][iroad]++;
		if (maze[down][right + 1][0] != 1)
			road[2][iroad]++;
		if (road[2][iroad] == 1 && iroad != 1)
		{
			for (int i = iroad; road[2][iroad] < 3; i--)
				iroad = i - 1;
			down = road[0][iroad];
			right = road[1][iroad];//传送到上一个岔路口
			maze[road[0][iroad + 1]][road[1][iroad + 1]][0] = 1;//改地图,封死死路入口
		}
		if (maze[down][right][1] != 0)
		{
			iroad = maze[down][right][1];
			down = road[0][iroad];
			right = road[1][iroad];//传送到上一个岔路口
			direction++;
		}
		else
			maze[down][right][1] = iroad;
		for (int i = 1; i <= 3; i++)
		{
			switch (direction % 4)
			{
			case 0:
			{
				if (maze[down - 1][right][0] == 1)
					direction--;
			}break;
			case 1:
			{
				if (maze[down][right - 1][0] == 1)
					direction++;
			}break;
			case 2:
			{
				if (maze[down + 1][right][0] == 1)
					direction++;
			}break;
			case 3:
			{
				if (maze[down][right + 1][0] == 1)
					direction--;
			}break;
			}
		}
		if (maze[down][right + 1][0] == 1 && maze[down + 1][right][0] == 1)
		{
			direction = 0;
		}
		switch (direction % 4)
		{
		case 0:down--; break;
		case 1:right--; break;
		case 2:down++; break;
		case 3:right++; break;
		}
	}
	for (int i = 1; i <= iroad; i++)
		cout << "(" << road[0][i]-1 << ", " << road[1][i]-1 << ")" << endl;
	cout << "(4, 4)";
	return 0;
}

转载于:https://my.oschina.net/u/4035395/blog/3011227

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值