Always Turn Left

来源:互联网 发布:mac装win10详细教程 编辑:程序博客网 时间:2024/06/05 19:42

http://code.google.com/codejam/contest/dashboard?c=agxjb2RlamFtLXByb2RyEAsSCGNvbnRlc3RzGIP6AQw#s=p1

 

Problem

You find yourself standing outside of a perfect maze. A maze is defined as "perfect" if it meets the following conditions:

  1. It is a rectangular grid of rooms, R rows by C columns.
  2. There are exactly two openings on the outside of the maze: the entrance and the exit. The entrance is always on the north wall, while the exit could be on any wall.
  3. There is exactly one path between any two rooms in the maze (that is, exactly one path that does not involve backtracking).

You decide to solve the perfect maze using the "always turn left" algorithm, which states that you take the leftmost fork at every opportunity. If you hit a dead end, you turn right twice (180 degrees clockwise) and continue. (If you were to stick out your left arm and touch the wall while following this algorithm, you'd solve the maze without ever breaking contact with the wall.) Once you finish the maze, you decide to go the extra step and solve it again (still always turning left), but starting at the exit and finishing at the entrance.

The path you take through the maze can be described with three characters: 'W' means to walk forward into the next room, 'L' means to turn left (or counterclockwise) 90 degrees, and 'R' means to turn right (or clockwise) 90 degrees. You begin outside the maze, immediately adjacent to the entrance, facing the maze. You finish when you have stepped outside the maze through the exit. For example, if the entrance is on the north and the exit is on the west, your path through the following maze would be WRWWLWWLWWLWLWRRWRWWWRWWRWLW:

If the entrance and exit were reversed such that you began outside the west wall and finished out the north wall, your path would be WWRRWLWLWWLWWLWWRWWRWWLW. Given your two paths through the maze (entrance to exit and exit to entrance), your code should return a description of the maze.

Input

The first line of input gives the number of cases, N. N test cases follow. Each case is a line formatted as

entrance_to_exit exit_to_entrance

All paths will be at least two characters long, consist only of the characters 'W', 'L', and 'R', and begin and end with 'W'.

Output

For each test case, output one line containing "Case #x:" by itself. The next R lines give a description of the R by C maze. There should be C characters in each line, representing which directions it is possible to walk from that room. Refer to the following legend:

Character   Can walk north?   Can walk south?   Can walk west?   Can walk east?   1YesNoNoNo2NoYesNoNo3YesYesNoNo4NoNoYesNo5YesNoYesNo6NoYesYesNo7YesYesYesNo8NoNoNoYes9YesNoNoYesaNoYesNoYesbYesYesNoYescNoNoYesYesdYesNoYesYeseNoYesYesYesfYesYesYesYes

Limits

1 ≤ N ≤ 100.

Small dataset

2 ≤ len(entrance_to_exit) ≤ 100,
2 ≤ len(exit_to_entrance) ≤ 100.

Large dataset

2 ≤ len(entrance_to_exit) ≤ 10000,
2 ≤ len(exit_to_entrance) ≤ 10000.

 

 

这个题目是走迷宫类算法的一个扩展, 按照左转优先法则走迷宫, 给出从入口到出口,和从出口到入口两条走法,要求还原迷宫.

没有验证能否还原出解, 解是否唯一, 我只是写了个算法, 还原出一个最小解, 就pass了.

基本想法是先创建一个原始迷宫, 迷宫每个点的4个方向状态都是Unknown, 然后按照路径走迷宫, 如果是L, 说明位置当前+0,是unpass,+90是pass, 如果是R, 说明当前位置+0, +90,+180都是unpass, 而+270是pass, 如果是RR(掉头), 说明位置当前+90,+0,+270都是unpass, 如果是w, 说明当前位置+0是pass,+90是unpass.同时下一个位置的+180是pass.

正着走一遍,然后掉头,再走回来, 最后输出每个点的状态就可以了.

 

数据结构用0,1,2,3分别来表示方向, 用&0x3(即%4)来做溢出保护, 减少了转方向的判断.

时间复杂度O(n), 空间复杂度(O(n*n)),主要是一开始不知道整个迷宫有多大,所以开辟了一块n*n的空间来作为最大迷宫,如果可以动态生成,空间复杂度会小很多.

 

代码:

#include <stdio.h>
#include <malloc.h>
#include <string.h>

#define MAX_LENGTH  (10004)
#define TYPE_UNKNOWN (0)
#define TYPE_PASS  (1)
#define TYPE_UNPASS  (2)

typedef struct tagNode
{
 char pPass[4];
 
} NODE, *LPNODE;
//east=0, south=1, west=2, north=3;

class Maze
{
private:
 NODE* m_Maze;
 int m_nWidth;
 int m_nHeight;
 int m_nLeft;
 int m_nRight;
 int m_nTop;
 NODE* m_pCur;
 int m_nCx;
 int m_nCy;
 int m_nDir;
public:
 Maze();
 ~Maze();
 void Clean();
 void TurnLeft();
 void TurnRight();
 void Turn180();
 void Move();
 void MoveOnly();
 void Print();
};

Maze::Maze()
{
 m_Maze = (NODE*)malloc(MAX_LENGTH*MAX_LENGTH*sizeof(NODE));
 Clean();
}

Maze::~Maze()
{
 free(m_Maze);
}

void Maze::Clean()
{
 memset(m_Maze, 0, MAX_LENGTH*MAX_LENGTH*sizeof(NODE));

 m_nWidth = MAX_LENGTH;
 m_nHeight = 1;
 m_nLeft = MAX_LENGTH/2;
 m_nRight = MAX_LENGTH/2;
 m_nCx = MAX_LENGTH/2;
 m_nCy = 0;
 m_nDir=1;
 m_pCur = m_Maze + m_nCx;
}

void Maze::TurnLeft()
{
 m_nDir += 3;
 m_nDir &= 0x3;
 m_pCur->pPass[m_nDir] = TYPE_PASS;
 
}

void Maze::TurnRight()
{
 m_nDir += 1;
 m_nDir &= 0x3;
 m_pCur->pPass[m_nDir] = TYPE_PASS;
 m_pCur->pPass[(m_nDir+3)&0x3] = TYPE_UNPASS;
 m_pCur->pPass[(m_nDir+2)&0x3] = TYPE_UNPASS;
}

void Maze::Turn180()
{
 m_nDir += 2;
 m_nDir &= 0x3;
 m_pCur->pPass[(m_nDir+3)&0x3] = TYPE_UNPASS;
 m_pCur->pPass[(m_nDir+2)&0x3] = TYPE_UNPASS;
 m_pCur->pPass[(m_nDir+1)&0x3] = TYPE_UNPASS;
}

void Maze::Move()
{
 m_pCur->pPass[m_nDir]=TYPE_PASS;
 switch(m_nDir)
 {
  case 0:m_nCx++;m_pCur++;if(m_nRight<m_nCx)m_nRight=m_nCx;break;
  case 1:m_nCy++;m_pCur+=m_nWidth;if(m_nHeight<m_nCy)m_nHeight=m_nCy;break;
  case 2:m_nCx--;m_pCur--;if(m_nLeft>m_nCx)m_nLeft=m_nCx;break;
  case 3:m_nCy--;m_pCur-=m_nWidth;break;
  default:break;
 }
 m_pCur->pPass[(m_nDir+2)&0x3]=TYPE_PASS;
}

void Maze::MoveOnly()
{
 m_pCur->pPass[m_nDir]=TYPE_PASS;
 switch(m_nDir)
 {
  case 0:m_nCx++;m_pCur++;break;
  case 1:m_nCy++;m_pCur+=m_nWidth;break;
  case 2:m_nCx--;m_pCur--;break;
  case 3:m_nCy--;m_pCur-=m_nWidth;break;
  default:break;
 }
 m_pCur->pPass[(m_nDir+2)&0x3]=TYPE_PASS;
}

void Maze::Print()
{
 int x, y;
 
 for(y=1; y<=m_nHeight; y++)
 {
  NODE* pLine = m_Maze + y * m_nWidth + m_nLeft;
  for(x=m_nLeft; x<=m_nRight; x++, pLine++)
  {
   int nVal=0;
   if(pLine->pPass[0]==TYPE_PASS) nVal+=8;
   if(pLine->pPass[1]==TYPE_PASS) nVal+=2;
   if(pLine->pPass[2]==TYPE_PASS) nVal+=4;
   if(pLine->pPass[3]==TYPE_PASS) nVal+=1;
   if(nVal<=9) nVal += '0';
   else nVal = nVal-10+'a';
   printf("%c", nVal);
  }
  printf("/n");
 }
}

int main()
{
 int nRound;
 int i, j;
 FILE* fp;
 char pFir[MAX_LENGTH], pSec[MAX_LENGTH];
 Maze maze;

 fp = fopen("1.txt", "r");
 fscanf(fp, "%d", &nRound);

 for(i=0; i<nRound; i++)
 {
  maze.Clean();

  fscanf(fp, "%s %s", pFir, pSec);
  for(j=0; j<MAX_LENGTH; j++)
  {
   if(pFir[j+1]=='/0') break;
   if(pFir[j]=='W') maze.Move();
   if(pFir[j]=='L') maze.TurnLeft();
   if(pFir[j]=='R')
   {
    if(pFir[j+1]=='R')
    {
     maze.Turn180();
     j++;
    }
    else
    {
     maze.TurnRight();
    }
   }
  }
  maze.MoveOnly();
  maze.Turn180();
  for(j=0; j<MAX_LENGTH; j++)
  {
   if(pSec[j+1]=='/0') break;
   if(pSec[j]=='W') maze.Move();
   if(pSec[j]=='L') maze.TurnLeft();
   if(pSec[j]=='R')
   {
    if(pSec[j+1]=='R')
    {
     maze.Turn180();
     j++;
    }
    else
    {
     maze.TurnRight();
    }
   }
  }
  maze.MoveOnly();
  printf("Case #%d:/n", i+1);
  maze.Print();
 }
 fclose(fp);
 return 0;
}