对应 NYOJ 题目:点击打开链接

师傅又被妖怪抓走了

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述

话说唐僧复得了孙行者,师徒们一心同体,共诣西方。自宝象国救了公主,承君臣送出城西,沿路饥餐渴饮,悟空便为师傅去化斋,等悟空回来,悟净慌慌张张的对悟空说:“不好了,不好了”,还没等悟净说完,悟空说:“师傅又被妖怪抓走了”,悟净:“NO!” ,悟空一脸茫然,悟净:“师傅和二师兄都被妖怪抓走了”。悟空(晕!)。为了防止悟空救人,妖怪先把唐憎和八戒分别藏起来,如果悟空在T分钟之后还没找到人,那必定是被妖怪吃掉了。假设悟空在一个n行m列的矩阵内,悟空在每一分钟可以走到上,下,左,右的其中的一个可以走的位置,每次只能走一步。我们把发现定义为可以直接看到对方,也就是说两个人在同一行或者同一列,并且中间没有障碍物或者没有其他人就可以看到对方。

输入
有多组测试数据,每组首先是三个正整数n , m (3<=n,m<=100), T,(0<=T<=100) 分别代表行数,列数,规定的时间。接下来n 行,每行 m 个字符。其中’ S ’ 代表悟空的位置,’ D ’代表师傅位置,’ E ’代表八戒的位置。并且保证都只有一个. ’ X ’代表墙 ,’ . ’代表空地 .
输出
每组先输出一行Case c:(c表示当前的组数,从1开始计数);
接下来一行,如果悟空可以在规定时间内找到两人,则输出最少需要的时间,否则输出-1。
样例输入
5 6 3
XXD...
....E.
....X.
....S.
......
5 6 3
XDX...
....E.
......
....S.
......
5 6 8
XXDX..
.XEX..
......
....S.
......
样例输出
Case 1:
-1
Case 2:
3
Case 3:
-1

题意:

中文题

思路:

首先拷贝一份地图,把 D 和 E 所在的行和列直接可达的空点分别用 D 和 E 填充,像这样:

 ==>     

其中,D 和 E 的交点要用另一个识别符(如 ‘H’ ),表示该点可以同时找到 D 和 E

然后从起点 S 进行 BFS,队列里的元素为:

typedef struct{int r, c; /* 横纵坐标 */int countD, countE; /* 在该点是否能找到 D,E */int step; /* 从起点到该点的步数 */
}Point;

BFS 是扩散式搜索,所以第一个符合题意的点(即 countD 和 countE 都不为 0,或者找到了D 和 E 的交点)就可以返回该点的 step。存在的问题是,该题很明显是可重复搜索,而一般 BFS 是不可重复的,如果像普通 BFS 那样只加个 vis[][] 标记已搜索的点,将得到错误的结果;如果不加 vis[][] 标记,答案是正确的,不过也很明显会超时。那怎么办?可以在 vis[][] 的前提下再加两个标记数组 visD[][] 和 visE[][],分别表示该点能否找到 D 或 E。接下来对于一个已经搜索过的点的坐标为 (x, y),它的父节点为 fa,如果 visD[x][y] != fa->countD || visE[x][y] != fa->countE(即该点与父节点的状态不一致),则这个点是可重复搜索的,否则是不可搜索。画图就能理解。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 110
#define QUE_SIZE 100000
char _map0[MAXN][MAXN];
char _map[MAXN][MAXN];
char vis[MAXN][MAXN];
char visD[MAXN][MAXN];
char visE[MAXN][MAXN];
int gr[4] = {-1, 0, 1, 0};
int gc[4] = {0, 1, 0, -1};
int n, m, t;typedef struct{int r, c; /* 横纵坐标 */int countD, countE; /* 在该点是否能找到 D,E */int step; /* 从起点到该点的步数 */
}Point;Point que[QUE_SIZE];/* 把 D 和 E 所在的行和列直接可达的空点分别用 D 和 E 填充 */
void change_point(char ch, int r, int c)
{int i;/* up */for(i = r-1; i >= 0; i--)if(_map[i][c] == '.' || _map[i][c] == 'S') _map[i][c] = ch;else if(_map0[i][c] == 'D' || _map0[i][c] == 'E' || _map0[i][c] == 'X') break;else if(_map[i][c] == 'D' || _map[i][c] == 'E') _map[i][c] = 'H';/* down */for(i = r+1; i < n; i++)if(_map[i][c] == '.' || _map[i][c] == 'S') _map[i][c] = ch;else if(_map0[i][c] == 'D' || _map0[i][c] == 'E' || _map0[i][c] == 'X') break;else if(_map[i][c] == 'D' || _map[i][c] == 'E') _map[i][c] = 'H';else break;/* left */for(i = c-1; i >= 0; i--)if(_map[r][i] == '.' || _map[r][i] == 'S') _map[r][i] = ch;else if(_map0[r][i] == 'D' || _map0[r][i] == 'E' || _map0[r][i] == 'X') break;else if(_map[r][i] == 'D' || _map[r][i] == 'E') _map[r][i] = 'H';else break;/* right */for(i = c+1; i < m; i++)if(_map[r][i] == '.' || _map[r][i] == 'S') _map[r][i] = ch;else if(_map0[r][i] == 'D' || _map0[r][i] == 'E' || _map0[r][i] == 'X') break;else if(_map[r][i] == 'D' || _map[r][i] == 'E') _map[r][i] = 'H';else break;
}/* 计算该点能找到谁 */
void get_count(Point *p)
{int r = p->r;int c = p->c;if(_map[r][c] == 'D'){p->countD = 1;}else if(_map[r][c] == 'E'){p->countE = 1;}else if(_map[r][c] == 'H'){p->countD = p->countE = 1;}
}int go_find(int sr, int sc)
{int i, j;int front, rear;Point sun;for(i = 0; i < n; i++){for(j = 0; j < m; j++){char ch = _map0[i][j];if(ch == 'D' || ch == 'E')change_point(ch, i, j);}}
#if 0for(i = 0; i < n; i++)printf("%s\n", _map[i]);
#endifmemset(vis, 0, sizeof(vis));memset(visD, 0, sizeof(visD));memset(visE, 0, sizeof(visE));front = 0;rear = 1;sun.r = sr;sun.c = sc;sun.countD = 0;sun.countE = 0;sun.step = 0;get_count(&sun);vis[sr][sc] = 1;visD[sr][sc] = sun.countD;visE[sr][sc] = sun.countE;que[front] = sun;_map0[sr][sc] = '.'; /* 起点也是可走的 */while(front < rear){Point cp, cpt;cp = cpt = que[front++];if(cp.step > t) /* 超过限制步数 */return -1;if(cp.countD && cp.countE){return cp.step;}for(i = 0; i < 4; i++){int r = cp.r + gr[i];int c = cp.c + gc[i];if(r >= 0 && r < n && c >= 0 && c < m && _map0[r][c] == '.'){if(!vis[r][c] || (visD[r][c] != cp.countD || visE[r][c] != cp.countE)){cp.r = r;cp.c = c;get_count(&cp);vis[r][c] = 1;visD[r][c] = cp.countD;visE[r][c] = cp.countE;cp.step++;que[rear++] = cp;cp = cpt;}}}}return -1;
}int main()
{
#if 0freopen("in.txt","r",stdin);
#endifint w = 0;while(~scanf("%d%d%d", &n, &m, &t)){int i, j, ans;int sr, sc;for(i = 0; i < n; i++){scanf("%s", _map[i]);for(j = 0; j < m; j++){if(_map[i][j] == 'S'){sr = i;sc = j;}}}for(i = 0; i < n; i++)strcpy(_map0[i], _map[i]);ans = go_find(sr, sc);printf("Case %d:\n", ++w);printf("%d\n", ans>t?-1:ans);}return 0;
}

可重复广搜 —— NYOJ 999 师傅又被妖怪抓走了相关推荐

  1. nyoj 999——师傅又被妖怪抓走了——————【双广搜】

    师傅又被妖怪抓走了 时间限制: 1000 ms  |  内存限制:65535 KB 难度: 3 描述 话说唐僧复得了孙行者,师徒们一心同体,共诣西方.自宝象国救了公主,承君臣送出城西,沿路饥餐渴饮,悟 ...

  2. nyoj 999 师傅又被妖怪抓走了

    师傅又被妖怪抓走了 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 话说唐僧复得了孙行者,师徒们一心同体,共诣西方.自宝象国救了公主,承君臣送出城西,沿路饥餐渴饮,悟空便 ...

  3. NYOJ 999 师傅又被妖怪抓走了(待续)

    题目链接 觉得自己现在的水平还是写不出这个程序的,网上说是预处理+双光搜+状态压缩,开始的时候我竟觉得是深搜,写着写着不对劲才发觉,当然预处理和双广搜和状态压缩都是第一次遇到,我还是先放一放,日后再来 ...

  4. NYOJ ~ 999 ~ 师傅又被妖怪抓走了(BFS+状压)

    思路:BFS.多加一个状态就可以了,状态的变化不是很好写.看代码理解吧. #include<bits/stdc++.h> using namespace std; const int MA ...

  5. nyist 999 师傅又被妖怪抓走了 【双广搜 || BFS +状态压缩】

    题目:nyist 999 师傅又被妖怪抓走了 分析:在一个图中只要看到D点和E点就行的最小步数,看到的定义是:也就是说两个人在同一行或者同一列,并且中间没有障碍物或者没有其他人就可以看到对方. 所以可 ...

  6. NYOJ999 师傅又被妖怪抓走了(预处理+状态压缩+广搜BFS)

    题目: 师傅又被妖怪抓走了 时间限制: 1000 ms  |  内存限制: 65535 KB 难度: 3 描述 话说唐僧复得了孙行者,师徒们一心同体,共诣西方.自宝象国救了公主,承君臣送出城西,沿路饥 ...

  7. NYOJ 师傅又被妖怪抓走了 双向BFS

    师傅又被妖怪抓走了 时间限制: 1000 ms  |  内存限制: 65535 KB 难度: 3 描述 话说唐僧复得了孙行者,师徒们一心同体,共诣西方.自宝象国救了公主,承君臣送出城西,沿路饥餐渴饮, ...

  8. nyoj999 师傅又被妖怪抓走了 (预处理+bfs+状态压缩)

    题目999 题目信息 执行结果 本题排行 讨论区 师傅又被妖怪抓走了 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描写叙述 话说唐僧复得了孙行者,师徒们一心同体,共诣西方.自宝 ...

  9. G - 非常可乐--重复广搜

    大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为.因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多.但see ...

最新文章

  1. 精通Spring Boot —— 第十五篇:使用@ControllerAdvice处理异常
  2. mysql 账号权限过期_Mysql用户忘记密码及密码过期问题的处理方法
  3. 最大公共子串提取“模式”
  4. P4503-[CTSC2014]企鹅QQ【字符串hash】
  5. mysql索引 红黑树_为什么MySql索引使用B+树?
  6. jQuery中id包含特殊字符,以及包含变量时处理。
  7. gluster安装完全指南
  8. Java对象转Map,Map转对象
  9. 英特尔的新方向:称王集成计算设备领域
  10. 用Python生成Hilbert矩阵
  11. Github全封41万俄罗斯开发者账号,开源真的无国界
  12. 如何用仅用C语言判断编译器的大小端
  13. RTSP、RTMP、HTTP流媒体播放器比较
  14. ida android so 断点,IDA Pro 7.0+调试Android so飘云整理(基于Android5.1.1)
  15. 十万,百万,千万,快狗打车架构是怎么演进的?
  16. 上帝在基督里赦免了所有人的罪
  17. 热点新闻管理系统设计与实现
  18. 【C++】常用math函数
  19. 数字图像隐藏图像的两种算法及实现代码
  20. JSP页面传值方法总结

热门文章

  1. 2024中国海洋大学计算机考研信息汇总
  2. Python中的水平制表符:\t
  3. Kubernetes and Cloud Native Meetup (北京站)最全资料下载
  4. 【HAVENT原创】JS 屏蔽/禁止双击选中文字
  5. 《我好想摆烂》(1)之SQL基础语法
  6. 代码随想录算法训练营第四十二天 | 01背包问题,你该了解这些、01背包问题,你该了解这些 滚动数组、 416. 分割等和子集
  7. Deformable DETR: DEFORMABLE TRANSFORMERSFOR END-TO-END OBJECT DETECTION(论文阅读)
  8. 电子商务驱动外贸行业前进 海外主机成加速器
  9. 微信小程序--学习 wepy
  10. kubespray v2.21.0 在线定制部署升级 kubernetes v1.24.0 集群【2】