728x90
https://www.acmicpc.net/problem/13787
미로가 주어졌을때 로봇의 최종 위치와 방향을 찾는 문제다.
로봇은 앞으로만 가며 앞이 벽이나 미로의 경계일때만 90도 방향 시계방향으로 회전한다.
DFS을 이용해서 풀어야하지만 이동횟수 L이 10^18까지 이므로 memoization 기법을 활용한다.
사이클을 찾기 위해 DFS로 한칸씩 이동하면서 그 칸에 최초로 도달한 이동횟수를 DP 배열에 기록한다.
(단 같은 칸이더라도 이동방향도 영향을 미치므로 dp배열에 방향까지 추가해준다. 크기 4* 100 *100)
그리고 최초로 DP 배열의 값이 -1이 아닌 값을 최초로 발견한 것은 사이클의 시작점이다. 그 지점에서 DFS를 멈추면 사이클의 주기를 구할 수 있다.)
이제 사이클의 시작지점과 주기를 찾았으므로 사이클 내에서 L일때의 위치와 방향을 구할수 있다.
(단 최종위치가 주기의 끝일 경우 예외사항이 있다. 이 예외사항만 처리해주면 끝)
3 3 16
E..
.*.
...
Answer : 1 1 N
Wrong : 1 1 E
package 백준;
import java.util.*;
import java.io.*;
public class InfinityMaze {
static class MyScanner{
BufferedReader bf;
StringTokenizer st;
MyScanner(){
bf = new BufferedReader(new InputStreamReader(System.in));
}
String next() {
if(st==null||!st.hasMoreTokens()) {
try {
st = new StringTokenizer(bf.readLine());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong() {
return Long.parseLong(next());
}
}
static class Point
{
int x;
int y;
int dir;
public Point(int x, int y,int dir) {
super();
this.x = x;
this.y = y;
this.dir = dir;
}
@Override
public String toString() {
return "Point [x=" + x + ", y=" + y + ", dir=" + dir + "]";
}
}
static long dp[][][];
static char map[][];
static int N,M;
static long L;
static int dx[] = {-1,0,1,0};
static int dy[] = {0,1,0,-1};
public static void main(String[] args) {
MyScanner sc = new MyScanner();
while(true) {
N = sc.nextInt();
M = sc.nextInt();
L = sc.nextLong();
if(N==0&&M==0&&L==0) break;
Point start = new Point(0,0,0);
map = new char[N][M];
dp = new long[4][N][M];
T = 0;
for(int i =0 ;i <4;i++) {
for(int j =0 ;j <N;j++)
Arrays.fill(dp[i][j], -1);
}
for(int i =0 ;i <N;i++) {
map[i] = sc.next().toCharArray();
for(int j =0 ;j<M;j++) {
if(map[i][j]=='E'||map[i][j]=='S'||map[i][j]=='N'||map[i][j]=='W') {
start.x = i;
start.y = j;
start.dir = toDir(map[i][j]);
}
}
}
dfs(start.x,start.y,start.dir,0);
if(T==0) { //사이클이 없는 경우
System.out.printf("%d %d %c\n",sx+1,sy+1,toChar(sd));
}
else {
int x = sx;
int y = sy;
int d = sd;
if((L-dp[sd][sx][sy])%T==0) { //사이클의 시작점인 경우
for(long i = 0; i < T;i++) {
int nx = x+dx[d];
int ny = y+dy[d];
int nd = d;
if(nx>=N||nx<0||ny<0||ny>=M||map[nx][ny]=='#') {
d = (nd+1)%4;
i--;
}else {
x = nx;
y = ny;
d = nd;
}
}
System.out.printf("%d %d %c\n",x+1,y+1,toChar(d));
continue;
}
for(long i =0 ;i <(L-dp[sd][sx][sy])%T;i++) { //사이클의 중간에서 끝난 경우
int nx = x+dx[d];
int ny = y+dy[d];
int nd = d;
if(nx>=N||nx<0||ny<0||ny>=M||map[nx][ny]=='#') {
d = (nd+1)%4;
i--;
}else {
x = nx;
y = ny;
d = nd;
}
}
System.out.printf("%d %d %c\n",x+1,y+1,toChar(d));
}
}
}
static long T;
static int sx,sy,sd;
private static void dfs(int x, int y, int dir, long t) {
if(dp[dir][x][y]!=-1) { //사이클 발견 시작지점 과 주기 저장
sx = x;
sy = y;
sd = dir;
T = t - dp[dir][x][y];
return;
}
dp[dir][x][y] = t;
if(t==L) { //사이클을 만나기전에 끝나는 경우
sx= x;
sy =y;
sd = dir;
return;
}
int nx = x+ dx[dir];
int ny = y+ dy[dir];
if(nx>=N||nx<0||ny<0||ny>=M||map[nx][ny]=='#') { //벽 만나서 회전
dir = (dir+1)%4;
dfs(x,y,dir,t);
}
else dfs(nx,ny,dir,t+1);
}
private static int toDir(char c) {
if(c=='N') return 0;
if(c=='E') return 1;
if(c=='S') return 2;
if(c=='W') return 3;
return 0;
}
private static char toChar(int d) {
if(d==0) return 'N';
if(d==1) return 'E';
if(d==2) return 'S';
if(d==3) return 'W';
return 'X';
}
}