对应 NYOJ 题目:点击打开链接
师傅又被妖怪抓走了
-
描述
-
话说唐僧复得了孙行者,师徒们一心同体,共诣西方。自宝象国救了公主,承君臣送出城西,沿路饥餐渴饮,悟空便为师傅去化斋,等悟空回来,悟净慌慌张张的对悟空说:“不好了,不好了”,还没等悟净说完,悟空说:“师傅又被妖怪抓走了”,悟净:“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 0
for(i = 0; i < n; i++)
printf("%s\n", _map[i]);
#endif
memset(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 0
freopen("in.txt","r",stdin);
#endif
int 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;
}