
NC14340:逃脱
发布日期:2021-05-08 20:00:21
浏览次数:18
分类:精选文章
本文共 5346 字,大约阅读时间需要 17 分钟。
题目描述
这是mengxiang000和Tabris来到幼儿园的第四天,幼儿园老师在值班的时候突然发现幼儿园某处发生火灾,而且火势蔓延极快,老师在第一时间就发出了警报,位于幼儿园某处的mengxiang000和Tabris听到了火灾警报声的同时拔腿就跑,不知道两人是否能够逃脱险境?
幼儿园可以看成是一个NM的图,在图中一共包含以下几种元素: “.”:表示这是一块空地,是可以随意穿梭的。 “#”:表示这是一块墙,是不可以走到这上边来的,但是可以被火烧毁。 “S”:表示mengxiang000和Tabris所在位子。 “E”:表示幼儿园的出口。 “”表示火灾发源地(保证输入只有一个火灾发源地)。 已知每秒有火的地方都会向周围八个格子(上下左右、左上、右上、左下、右下)蔓延火势.mengxiang000和Tabris每秒都可以选择周围四个格子(上下左右)进行移动。(假设两人这一秒行动完之后,火势才蔓延开) 根据已知条件,判断两人能否成功逃脱险境,如果可以,输出最短逃离时间,否则输出T_T。
输入描述
第一行输入一个整数t,表示一共的测试数据组数。
第二行输入两个整数n,m,表示幼儿园的大小。 接下来n行,每行m个字符,表示此格子是什么元素。 t<=200 3<=n<=30 3<=M<=30 保证图中有一个起点,一个出口,一个火灾源处.
输出描述
每组数据输出一行,如果两人能够成功到达出口,那么输出最短逃离时间,否则输出T_T
题目分析1
1.数据存储方式:
通过结构体把图中的每个格子进行存储,包含格子的坐标,以及到达该格子的时间,并在创建时对其初始化。struct Point{ int x,y,time; Point(){ time = 0; } Point(int a, int b, int c):x(a),y(b),time(c){}};
2.解题思路:
1)首先对fire进行一次bfs搜索,记录fire蔓延到每一个格子所需要的时间。 2)对人进行bfs搜索找到到达出口的最短消耗时间,注意如果在最短的消耗时间内也无法安全逃离,则无法逃离成功。 3)通过到达的时间与火势蔓延到该格子的时间进行比较,进行剪枝。3.AC代码
#includeusing namespace std;const int maxn = 35;int n,m,t,ans; ///ans 是正常出来的最短时间char graph[maxn][maxn];bool vis[maxn][maxn] = { 0};int fire[maxn][maxn] = { 0}; ///记录fire到每一个格所需要时间///前四个是上下左右,后四个是左上,右上,左下,右下int dir[][2] = { { 1,0} , { -1,0} , { 0,1} , { 0,-1}, { 1,1} , { -1,-1} , { -1,1} , { 1,-1}};struct Point{ int x,y,time; Point(){ time = 0; } Point(int a, int b, int c):x(a),y(b),time(c){ }}fi,st;void bfs_fire(){ memset(vis,false,sizeof(vis)); memset(fire,0,sizeof(fire)); queue que; que.push(fi); vis[fi.x][fi.y] = true; while(!que.empty()){ Point head = que.front(); que.pop(); for (int i = 0;i < 8;i ++){ int nx = head.x + dir[i][0]; int ny = head.y + dir[i][1]; if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue; ///越界 if (vis[nx][ny]) continue; vis[nx][ny] = true; fire[nx][ny] = head.time + 1; ///计算每个点有或是蔓延到的时间 que.push({ nx , ny , head.time + 1}); } }}bool bfs(){ memset(vis,0,sizeof(vis));///重新初始vis数组 queue que; que.push(st); vis[st.x][st.y] = true; while (!que.empty()){ Point head = que.front(); que.pop(); for (int i = 0;i < 4;i ++){ int nx = head.x + dir[i][0]; int ny = head.y + dir[i][1]; if (nx < 0 || nx >= n || ny < 0 || ny >= m) continue; ///越界 if (vis[nx][ny]) continue; if (graph[nx][ny] == '#') continue; if (graph[nx][ny] == 'E' && head.time + 1 <= fire[nx][ny]) { ///人先到入口,火才到 ans = head.time + 1; return true; } if (head.time + 1 < fire[nx][ny]){ ///要严格小于,== 时本秒结束火就到了 vis[nx][ny] = true; que.push({ nx , ny , head.time + 1}); } } } return false;}int main(){ cin >> t; while (t --){ cin >> n >> m; for (int i = 0;i < n;i ++){ for(int j = 0;j < m;j ++){ cin >> graph[i][j]; if (graph[i][j] == 'S'){ st.x = i; st.y = j; } else if (graph[i][j] == '*'){ fi.x = i; fi.y = j; } } } bfs_fire(); if (bfs()) cout << ans << endl; else cout << "T_T" << endl; } return 0;}
题目分析2
在网上浏览学习到了一个更简单的方法,采用切比雪夫距离进行求解,代码量直接减少一半(T_T),去掉了上述中的dfs_fire()方法。可能有很多和我一样,初次听到切比雪夫距离这个概念,所以首先简单的介绍一下原理:
切比雪夫距离:
指二个点之间的距离定义为其各座标数值差绝对值的最大值。以(x1,y1)和(x2,y2)二点为例,其切比雪夫距离为max(|x2-x1|,|y2-y1|)。下图展示了图中黄冠到各点的切比雪夫距离:![]()
AC代码:
#includeusing namespace std;const int maxn = 35;int n,m,t,ans; ///ans 是正常出来的最短时间char graph[maxn][maxn];bool vis[maxn][maxn] = { 0};///上下左右int dx[] = { 0,0,1,-1};int dy[] = { 1,-1,0,0};struct Point{ int x,y,time; Point(){ time = 0; } Point(int a, int b, int c):x(a),y(b),time(c){ }}fi,st;int bfs(){ memset(vis,0,sizeof(vis)); queue que; que.push(st); vis[st.x][st.y] = true; while (!que.empty()){ Point head = que.front(); que.pop(); head.time ++; for (int i = 0;i < 4;i ++){ int nx = head.x + dx[i]; int ny = head.y + dy[i]; if (nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny] || graph[nx][ny] == '#') continue; ///不满足条件的格子 越界、已访问过、墙壁 if(graph[nx][ny] == 'E') { //如果火到达终点所需要的时间,大于人走到这里的时间,说明能正常出去,返回时间 if(max(abs(nx - fi.x), abs(ny - fi.y)) >= head.time) return head.time; } if(max(abs(nx - fi.x), abs(ny - fi.y)) <= head.time) continue; vis[nx][ny] = true; que.push({ nx, ny, head.time}); } } return -1;}int main(){ cin >> t; while (t --){ cin >> n >> m; for (int i = 0;i < n;i ++){ for(int j = 0;j < m;j ++){ cin >> graph[i][j]; if (graph[i][j] == 'S'){ st.x = i; st.y = j; } else if (graph[i][j] == '*'){ fi.x = i; fi.y = j; } } } int ans = bfs(); if (ans != -1) cout << ans << endl; else cout << "T_T" << endl; } return 0;}
发表评论
最新留言
路过,博主的博客真漂亮。。
[***.116.15.85]2025年03月22日 23时28分39秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Java集合总结系列2:Collection接口
2019-03-06
Linux学习总结(九)—— CentOS常用软件安装:中文输入法、Chrome
2019-03-06
比技术还重要的事
2019-03-06
linux线程调度策略
2019-03-06
软中断和实时性
2019-03-06
Linux探测工具BCC(可观测性)
2019-03-06
SNMP介绍及使用,超有用,建议收藏!
2019-03-06
HDU5589:Tree(莫队+01字典树)
2019-03-06
不停机替换线上代码? 你没听错,Arthas它能做到
2019-03-06
Python开发之序列化与反序列化:pickle、json模块使用详解
2019-03-06
采坑 - 字符串的 "" 与 pd.isnull()
2019-03-06
无序列表 - 链表
2019-03-06
Matplotlib绘制漫威英雄战力图,带你飞起来!
2019-03-06
机器学习是什么
2019-03-06
《小王子》里一些后知后觉的道理
2019-03-06
《你当像鸟飞往你的山》总结
2019-03-06
《我是猫》总结
2019-03-06
《抗糖化书》总结
2019-03-06
apache虚拟主机配置
2019-03-06
PHP官方网站及PHP手册
2019-03-06