AOJ2320 Infinity Maze

問題リンク Infinity Maze

  • 概要

後回し

  • 解法

u[H][W][D]: (H, W)に向きDで最初に到達したときのステップ数
という表を作って行きます。
10^18もステップがありますが、ボード上の状態は40000しかないので、必ずどこかでループが生じます。
長さKのループに入ったら、シミュレートするべき残りステップ数は一気にK未満に化けます。

  • ソース
import java.util.Scanner;

//Infinity Maze
public class AOJ2320 {
	
	int[][] move = {{-1,0},{0,1},{1,0},{0,-1}};
	char[] str = {'N','E','S','W'};
	
	int h, w;
	long L;
	
	void run()  {
		Scanner sc = new Scanner(System.in);
		for(;;){
			h = sc.nextInt(); w = sc.nextInt(); L = sc.nextLong();
			if((h|w|L)==0)break;
			char[][] map = new char[h][w];
			int si = 0, sj = 0, d = 0;
			for(int i=0;i<h;i++){
				map[i] = sc.next().toCharArray();
				for(int j=0;j<w;j++){
					if(map[i][j]=='N'){
						map[i][j] = '.';
						si = i; sj = j; d = 0;
					}
					else if(map[i][j]=='E'){
						map[i][j] = '.';
						si = i; sj = j;d = 1;
					}
					else if(map[i][j]=='S'){
						map[i][j] = '.';
						si = i; sj = j;d = 2;
					}
					else if(map[i][j]=='W'){
						map[i][j] = '.';
						si = i; sj = j;d = 3;
					}
				}
			}
			long[][][] u = new long[h][w][4];
			for(int i=0;i<h;i++)for(int j=0;j<w;j++)for(int k=0;k<4;k++)u[i][j][k] = -1;
			u[si][sj][d] = 0;
			long step = 1;
			boolean skip = false;
			while(step<=L){
				int ni = si+move[d][0], nj = sj+move[d][1];
				for(;;){
					if(0<=ni&&ni<h&&0<=nj&&nj<w&&map[ni][nj]!='#')break;
					d = (d+1)%4;
					ni = si+move[d][0]; nj = sj+move[d][1];
				}
				si = ni; sj = nj;
				if(u[ni][nj][d]==-1||skip){
					u[ni][nj][d] = step;
				}
				else{
					skip = true;
					long dif = step-u[si][sj][d];
					long x = L - step;
					x%=dif;
					step = L-x;
				}
				step++;
			}
			System.out.println((si+1)+" "+(sj+1)+" "+str[d]);
		}
	}
	
	public static void main(String[] args) {
		new AOJ2320().run();
	}
}