2019第十届蓝桥杯国赛C组C/C++第I题 胖子走迷宫

2019第十届蓝桥杯国赛C组C/C++第I题 胖子走迷宫

这次C组的题目突然比以前加大了难度,但如果想明白了,其实还是特别简单。
这道题当时卡了我将近两个小时,一直处于放弃和不放弃的边缘,最终心态爆炸,间接地让我没拿到一等奖。
当天吃完饭就和老师同学们一起逛长安街,放空了心态,一直到了晚上,回来洗了个澡,始终睡不着,突然听同房的同学一句话,顿时醒悟,然后尝试做了一下,居然做出来了。
总而言之,还是训练少了,拿到新题目,总会有束手无策之感,希望第二次来北京的时候,可以上领奖台。

题目简介

有一个n*m的迷宫(可能原题是边长为n的正方形迷宫,但我记不太清了,都差不多),+为平地*为墙(我做的时候没想起来,用0代表空地,1代表了墙,一个意思),有一个大胖子,在时间单位为0的时候,占5×5的方格,每次时间单位都可以选择停顿和走一步,给定一个正整数k,在第k时间单位结束的那一刻,胖子会变瘦,占3×3的方格,在第2k时间单位结束的那一刻,胖子再次变瘦,变成只占1×1方格。起始点为(3,3),结束点为(n-2,m-2)。问走出迷宫最短要多长时间。

输入

第一行三个正整数n,m,k,表示迷宫的长,高和k
后面n行每行m个字符,代表迷宫的状态

输出

一个整数,表示最短要多长时间。

测试用例
输入:
9 9 5
000000000
000000000
000000000
000000000
000000000
111011111
000000000
000000000
000000000
输出:
16

想明白了其实很简单,条件BFS,
普通BFS上,加入时间限制,根据时间判断有多胖,
再在每次循环取出节点,进行上下左右遍历之前(之后也行),将节点本身放入队列,代表站着不动
就这样就OK了,注意好各种细节就OK,下面是代码
如果有兴趣的话,还可以做出优化,比如2k时间之后不再加入站着不动的情况、优化胖形态的能否行走判断等等

#include <iostream>
#include <queue>

using namespace std;

int n, m;
int k;
//用于记录
char maze[3010][3010];
bool vis[3010][3010] = { 0 };
//记录第i*k个时间点有多胖,不放心的话,这个数组可以开大一点
int fat_record[100000] = { 2, 1, 0 };		
//用于移动
int move_x[4] = { -1,1,0,0 };
int move_y[4] = { 0,0,-1,1 };

//节点记录纵横坐标和该节点的时间
struct node
{
	int x;
	int y;
	int time;
};

void bfs()
{
	//一个装节点的队列,用于bfs
	queue<node> que;

	//将初始节点放入队列
	vis[3][3] = true;
	que.push({ 3, 3, 0 });

	//开始bfs
	while (!que.empty())
	{
		node temp = que.front();
		que.pop();
	
		//当前节点的位置满足条件,则输出当前节点中记录的位置
		if (temp.x == n - 2 && temp.y == m - 2)
		{
			cout << temp.time << endl;
			break;
		}

		//直接将站着不动的情况放入队列
		que.push({ temp.x, temp.y, temp.time + 1 });

		//往四个方向枚举
		for (int i = 0; i < 4; i++)
		{
			int cachex = temp.x + move_x[i];
			int cachey = temp.y + move_y[i];
			int fat = fat_record[(temp.time) / k];

			//判断是否访问过
			if (vis[cachex][cachey] != false)
				continue;

			//是否出边界
			if (1 > cachex - fat || cachex + fat > n || 1 > cachey - fat || cachey + fat > n)
				continue;

			//计算是否能走到下一个格子
			int flag = false;
			if (fat != 0)
			{
				for (int i = cachex - fat; i <= cachex + fat; i++)
				{
					for (int j = cachey - fat; j <= cachey + fat; j++)
					{
						if (maze[i][j] != '0')
							flag = true;
					}
				}
			}
			else
			{
				if (maze[cachex][cachey] != '0')
					flag = true;
			}
			if (flag != false)
				continue;

			//放入节点
			vis[cachex][cachey] = true;
			que.push({ cachex, cachey, temp.time + 1 });
		}
	}
}

int main()
{
	cin >> n >> m >> k;

	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			cin >> maze[i][j];

	bfs();

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值