撒哈拉大冒险
Time Limit: 1000 ms Case Time Limit: 1000 ms Memory Limit: 64 MB
Total Submission: 193 Submission Accepted: 14
Total Submission: 193 Submission Accepted: 14
Description
在撒哈拉大沙漠中,有一个神奇的迷宫,那是所有冒险,探索者都想要破解的圣地。
迷宫是由多块相同的子迷宫紧凑拼接而成,每一个子迷宫的规模为n*m,整个迷宫是无限大的。
大意为对于某一块迷宫,他的上下左右,都是拥有相同的布局的迷宫,而且方向一致,不可旋转。
这样便遗留下了一个问题,从入口出发之后,每次只能往上下左右四个方向移动,在不重复走同一个位置的前提下,整个迷宫是否可以无限走下去。
很多探险家便是在迷宫里累死的。请帮助cxlove判断迷宫是否是可以无限走下去。
迷宫是由多块相同的子迷宫紧凑拼接而成,每一个子迷宫的规模为n*m,整个迷宫是无限大的。
大意为对于某一块迷宫,他的上下左右,都是拥有相同的布局的迷宫,而且方向一致,不可旋转。
这样便遗留下了一个问题,从入口出发之后,每次只能往上下左右四个方向移动,在不重复走同一个位置的前提下,整个迷宫是否可以无限走下去。
很多探险家便是在迷宫里累死的。请帮助cxlove判断迷宫是否是可以无限走下去。
Input
一个整数T,表示T组数据。(1<=T<=100)
对于每组数据:
两个整数n,m。(1<=n,m<=1000)
接下来n行,每行m个字符。描述整个迷宫。‘S’表示入口位置,‘.’表示该位置可以到达,‘#’表示该位置为障碍物,不可到达。
对于每组数据:
两个整数n,m。(1<=n,m<=1000)
接下来n行,每行m个字符。描述整个迷宫。‘S’表示入口位置,‘.’表示该位置可以到达,‘#’表示该位置为障碍物,不可到达。
Output
对于每组数据,如果可以无限走下去,输出“YES”,否则输出“NO”。
Sample Input
Original | Transformed |
3 3 3 ... #S# ### 5 4 ##.# ##S# #..# #.## #..# 4 4 #### #..# #S.# ####
Sample Output
Original | Transformed |
YES YES NO
Hint
Sample 1:
从入口出发,然后向走一步,由于第一行全部都为空地,所以可以一直往左或者往右走,便会无限移动下去。
从入口出发,然后向走一步,由于第一行全部都为空地,所以可以一直往左或者往右走,便会无限移动下去。
Source
安徽大学第五届ACM/ICPC程序设计竞赛 现场赛
————————————————————害羞的分割线————————————————————
思路:一看到走迷宫,想起来DFS和BFS。但是选择哪个更好呢?直觉告诉我DFS+剪枝……咳咳,其实是因为刚做了HDU的Temper of the Bone啦!题目大致是迷宫可以无限拼接。我们把迷宫放在正当中,在它的上下左右增加复制的迷宫,看从中间的S点是否能走到其他的S点。
分析之后,我们发现1000×1000的图扩展成9张太浪费。于是精简成3张,留下右边和下边。该思路可行。但是写出来之后TLE了。
然后思考,是否不必走到另一个S点。毕竟走到另一个S点意味着很多很多耗时。询问之后得到了另一个思路,就是只走一张图,如果从S点出发后,「越界」走出这张图,之后坐标“改”成「非越界」,也就是模拟了走到另外一张完全相同的迷宫当中。
最后,考虑一下需要的数组。首先是栈sta[ ]、vis[ ](结构体),之后是地图mat[ ][ ]。重要变量:ox、oy,nx、ny。前者是相对坐标,后者是当前的绝对坐标。方法:(x Mod m + m)Mod m
代码如下:
//方法:栈+相对位置(模拟)
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}, l, r, sx, sy;
char mat[1010][1010];
const int IMP = 0x7f7f7f7f;//这是一个相当大的值,作为“不可能”访问到的值
typedef struct{
int x, y;
}Node;//利用压缩的方法储存下标会遇到很多问题,比如负数下标,在本方法中是可能的
Node vis[1010][1010], sta[1000100];//vis[]数组保存已访问的下标。
bool dfs() {
int top = -1;
for(int i = 0; i < l; i++)
for(int j = 0; j < r; j++)
vis[i][j].x = vis[i][j].y = IMP;//初始化vis[]
Node u;
u.x = sx; u.y = sy;
sta[++top] = vis[sx][sy] = u;//起点进栈
while(top != -1) {
u = sta[top--];//更新u为当前栈首,同时出栈
for(int d = 0; d < 4; d++) {
int nx = u.x + dx[d], ny = u.y + dy[d];//绝对位置
int ox = (nx%l + l)%l, oy = (ny%r + r)%r;//相对位置
if(mat[ox][oy] == '#') continue;//相对位置是'#',无法在此处扩展迷宫
if(vis[ox][oy].x == IMP) {//IMP表示没有访问过
sta[++top].x = vis[ox][oy].x = nx;//进栈并储存该相对位置的绝对位置
sta[top].y = vis[ox][oy].y = ny;
}
else if(vis[ox][oy].x != nx||vis[ox][oy].y != ny) return true;//该相对位置已访问?有可能无限扩展!绝对位置不同?一定无限!
}
}
return false;
}
int main() {
int cas;
scanf("%d", &cas);
while(cas--) {
scanf("%d%d", &l, &r);
for(int i = 0; i < l; i++) {
scanf("%s", mat[i]);
for(int j = 0; j < r; j++) {
if(mat[i][j] == 'S') {
sx = i;
sy = j;
}
}
}//储存地图并记录起点位置
if(dfs()) puts("YES");
else puts("NO");
}
return 0;
}