土下座しながら探索中

主に競技プログラミング

AOJ 2320:Infinity Maze

問題リンク:Infinity Maze | Aizu Online Judge

問題概要:
H*W(1 <= H,W <= 100)の迷路と可能なステップ数L(1 <= L <= 10^18)が与えられる
迷路の中には1つロボットが置いてある
そのロボットをL回動かした後に居るセルとロボットが向いている方向を答えろ

ロボットが壁、または迷路の外にでようとしたときは右に90度回転する
これはステップにカウントしない

解法:
visited[y][x][dir] := セル(x,y)に方向dirを向いて最初にきたときのステップ数
という配列を用意してシュミレーションする
配列は最初-1で初期化しておき、今後訪れたセルの値が-1でないのであればそこはループになっているのでループにかかる回数でmodをとり残りを再度シュミレーションする
Lが最大10^18なのでintでとるとTLEになるので注意

コード:

#include<iostream>
#include<algorithm>
#include<vector>
#include<cassert>
#define F first
#define MAX 1000
#define S second
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
using namespace std;
typedef pair<int,int> P;
struct Pox
{
  int x,y,dir;
  Pox(int x=-1,int y=-1,int dir=-1):x(x),y(y),dir(dir){}
};
int dx[] = {+0,+1,+0,-1};//N,E,S,W
int dy[] = {-1,+0,+1,+0};
char G[MAX][MAX];
int visited[MAX][MAX][4];
P src;

int getDir(char c)
{
  switch(c)
    {
    case 'N':
      return 0;
    case 'E':
      return 1;
    case 'S':
      return 2;
    case 'W':
      return 3;
    }
}

char toChar(int c)
{
  switch(c)
    {
    case 0:
      return 'N';
    case 1:
      return 'E';
    case 2:
      return 'S';
    case 3:
      return 'W';
    }
}

int main()
{
  int H,W;
  long long L;
  while(cin >> H >> W >> L,H|W|L)
    {
      int dir;
      rep(i,H)
	{
	  string line;
	  cin >> line;
	  rep(j,line.size())
	    {
	      assert(j < W);
	      G[i][j] = line[j];
	      if(!(G[i][j] == '.' || G[i][j] == '#'))src = P(j,i),dir = getDir(G[i][j]),G[i][j] = '.';
	      
	      rep(k,4)visited[i][j][k] = -1;
	    }
	}     

      long long phase = 0;
      vector<Pox> path;
      path.push_back(Pox(src.F,src.S,dir));

      while(true)
	{
	  if(phase >= L)
	    {
	      cout << src.S+1 << " " << src.F+1 << " " << toChar(dir) << endl;  
	      break;
	    }
	  if(visited[src.S][src.F][dir] != -1)
	    { 
	      L -= phase;
	      L %= (phase-visited[src.S][src.F][dir]);
	      L += (phase-visited[src.S][src.F][dir]);
	      for(int i=0;i<L;i++)
		{
		  src.F += dx[dir];
		  src.S += dy[dir];
		  
		  if(!(0 <= src.F && src.F < W && 0 <= src.S && src.S < H))
		    {
		      src.F -= dx[dir];
		      src.S -= dy[dir];
		      dir = (dir+1)%4;
		      i--;
		      continue;
		    }
		  else if(G[src.S][src.F] == '#')
		    {
		      src.F -= dx[dir];
		      src.S -= dy[dir];
		      dir = (dir+1)%4;
		      i--;
		      continue;
		    }	
		}
	   
	      cout << src.S+1 << " " << src.F+1 << " " << toChar(dir) << endl;
	      
	      break;
	    }     
 
	  visited[src.S][src.F][dir] = phase;
	  src.F += dx[dir];
	  src.S += dy[dir];
	  if(!(0 <= src.F && src.F < W && 0 <= src.S && src.S < H))
	    {
	      src.F -= dx[dir];
	      src.S -= dy[dir];
	      dir = (dir+1)%4;
	      continue;
	    }
	  else if(G[src.S][src.F] == '#')
	    {
	      src.F -= dx[dir];
	      src.S -= dy[dir];
	      dir = (dir+1)%4;
	      continue;
	    }
 
	  path.push_back(Pox(src.F,src.S,dir));
	  phase++;
	}
      

    }
  return 0;
}