Abbott的复仇(Abbott's Revenge)ACM/ICPC WF2000

Abbott's Revenge

Time limit: 3.000 seconds

     The 1999 World FinalsContest included a problem based on a “dicemaze.” At the time the problem was written, the judges were unable todiscover the original source of the dice maze concept. Shortly afterthe contest, however, Mr. Robert Abbott, the creator of numerous mazesand an author on the subject, contacted the contest judges andidentified himself as the originator of dice mazes. We regret that wedid not credit Mr. Abbott for his original concept in last year’sproblem statement. But we are happy to report that Mr. Abbott hasoffered his expertise to this year’s contest with his original andunpublished “walk-through arrow mazes.”

    As are most mazes, awalk-through arrow maze is traversed by moving from intersection tointersection until the goal intersection is reached. As eachintersection is approached from a given direction, a sign near theentry to the intersection indicates in which directions theintersection can be exited. These directions are always left, forwardor right, or any combination of these.

     Figure 1 illustrates awalk-through arrow maze. The intersections are identified as “(row,column)” pairs, with the upper left being (1,1). The “Entrance”intersection for Figure 1 is (3,1), and the “Goal” intersection is(3,3). You begin the maze by moving north from (3,1). As you walk from(3,1) to (2,1), the sign at (2,1) indicates that as you approach (2,1)from the south (traveling north) you may continue to Goonly forward.Continuing forward takes you toward (1,1). The sign at (1,1) as youapproach from the south indicates that you may exit (1,1) only bymaking a right. This turns you to the east now walking from (1,1)toward (1,2). So far there have been no choices to be made. This isalso the case as you continue to move from (1,2) to (2,2) to (2,3) to(1,3). Now, however, as you move west from (1,3) toward (1,2), you havethe option of continuing straight or turning left. Continuing straightwould take you on toward (1,1), while turning left would take you southto (2,2). The actual (unique) solution to this maze is the followingsequence of intersections: (3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3)(1,2) (1,1) (2,1) (2,2) (1,2) (1,3) (2,3) (3,3).

You must write a programto solve valid walk-through arrow mazes. Solving a maze means (ifpossible) finding a route through the maze that leaves the Entrance inthe prescribed direction, and ends in the Goal. This route should notbe longer than necessary, of course. But if there are several solutionswhichare equally long, you can chose any of them.

     The input file willconsist of one or more arrow mazes. The first line of each mazedescription contains the name of the maze, which is an alphanumericstring of no more than 20 characters. The next line contains, in thefollowing order, the starting row, the starting column, the startingdirection, the goal row, and finally the goal column. All are delimitedby a single space. The maximum dimensions of a maze for this problemare 9 by 9, so all row and column numbers are single digits from 1 to9. The starting direction is one of the characters N, S, E or W,indicating north, south, east and west, respectively.

All remaining inputlines for a maze have this format: two integers, one or more groups ofcharacters, and a sentinel asterisk, again all delimited by a singlespace. The integers represent the row and column, respectively, of amaze intersection. Each character group represents a sign at thatintersection. The first character in the group is N, S, E or W toindicate in what direction of travel the sign would be seen. Forexample, S indicates that this is the sign that is seen when travellingsouth. (This is the sign posted at the north entrance to theintersection.) Following this first direction character are one tothree arrow characters. These can be L, F or R indicating left,forward, and right, respectively.

      The list ofintersections is concluded by a line containing a single zero in thefirst column. The next line of the input starts the next maze, and soon. The end of input is the word END on a single line by itself.

    For each maze, theoutput file should contain a line with the name of the maze, followedby one or more lines with either a solution to the maze or the phrase“No Solution Possible”. Maze names should start in column 1, and allother lines should start in column 3, i.e., indented two spaces.Solutions should be output as a list of intersections in the format“(R,C)” in the order they are visited from the start to the goal,should be delimited by a single space, and all but the last line of thesolution should contain exactly 10 intersections.

The first maze in thefollowing sample input is the maze in Figure 1.



Sample InputOutput for the Sample Input
SAMPLE
3 1 N 3 3
1 1 WL NR *
1 2 WLF NR ER *
1 3 NL ER *
2 1 SL WR NF *
2 2 SL WF ELF *
2 3 SFR EL *
0
NOSOLUTION
3 1 N 3 2
1 1 WL NR *
1 2 NL ER *
2 1 SL WR NFR *
2 2 SR EL *
0
END
SAMPLE
  (3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1) (2,1)
  (2,2) (1,2) (1,3) (2,3) (3,3)
NOSOLUTION
  No Solution Possible



Figure 1: An Example Walk-ThroughArrow Maze



Figure 2: Robert Abbott’s AtlantaMaze

      Robert Abbott’swalk-through arrow mazes are actually intended forlarge-scale construction, not paper. Although his mazes areunpublished, some of them have actually been built. One of these is ondisplay at an Atlanta museum. Others have been constructed by theAmerican Maze Company over the past two summers. As their name suggeststhese mazes are intended to be walked through.

      For the adventurous, Figure 2 is a graphic of Robert Abbott’sAtlanta maze. Solving it isquite difficult, even when you have an overview of the entire maze.Imagine trying to solve this by actually walking through the maze andonly seeing one sign at a time! Robert Abbott himself indicated thatthe maze is too complex and most people give up before finishing. Amongthe people that did not give up was Donald Knuth: it took him aboutthirty minutes to solve the maze.

本题大意:
有一个最多包含9*9个交叉点的迷宫。输入起点、离开起点时的朝向和终点,求一条最短路。
解题思路:普通的迷宫问题最短路的问题,利用BFS广搜另加队列的方法可以得到解决。本题通过设置每一个节点的状态进行了路径的限制,这和我们生活中的车道异曲同工之妙,可见此题很好的映射到了实际生活中。我们处于城市街道的某一个位置的时候要明白我们的朝向、所处的行车道(这里指的是车道限制你能走的方向),在满足此条件下,找出最短路。本题和普通的迷宫在本质上是一样的,但是由于朝向也起到了关键性的作用,所以需要用一个三元组(r,c,dir)表示位于(r,c),面向dir这个状态,即快要到达某一点时, 你需要根据你朝向的方向去确定下一步要怎么走,此处用d[r][c][dir]表示初始状态到此状态的最短路,并且用p[r][c][dir]来保存此状态的前一个位置信息。***在套用BFS框架之前,需要明确图中的节点包含哪些信息?
代码长,我们一点一点地做预备工作:首先将四个方向和三种转弯的方式进行编码,提供了相应的转化函数:
const char* dirs = "NESW";  
const char* turns = "FLR";  
int dir_id(char c) {  
    return (strchr(dirs, c) - dirs);  
}  
int turn_id(char c) {  
    return (strchr(turns, c) - turns);  
}  
strchr返回了字符c在字符串dirs中的位置,返回其标号,注意到一点小的细节,dirs中的方向的顺序是顺时针旋转,这一点的技巧性在之后能够体现出来。
const int dr[] = {-1, 0, 1, 0};  
const int dc[] = {0, 1, 0, -1}; 
根据转弯方式和当前的状态,计算出下一步的状态。
Node walk(const Node& u, int turn) {  
    int dir = u.dir;//改变朝向  
    if (turn == 1) dir = (dir + 3) % 4;  
    if (turn == 2) dir = (dir + 1) % 4;  
    //r + dr[dir], c + dc[dir]表示在(r, c)位置朝dir方向前进一格。  
    //所以向左转或向右转时,我们只要先改变朝向后再让原先的行r加上dr[dir]和列c加上dc[dir]就行了  
    return Node(u.r + dr[dir], u.c + dc[dir], dir);  
}  

#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
const char*dirs="NESW";
condt char*turns="FLR";
const int maxn=20;
string maze_name;
int r0, c0, r1, c1, dir, r2, c2;  
int has_edge[maxn][maxn][maxn][maxn];//代表在某一位置的某一朝向向某个方向走有无路

void read()
{
    memset();
    int pr,pc,pdir,pturn;
    string temp;
    while(cin>>pr)
    {
        if(pr==0)
            break;
        cin>>pc;
        while(cin>>temp)
        {
            if(temp=="*") break;
            pdir=dir_id(temp[0]);//取字符串的第一个的字符作为面朝的方向
            for(int i=1;i<temp.length();i++)
            {
                pturn=turn_id(temp[i]);
                has_edge[pr][pc][pdir][pturn]=1;
            }
        }
    }
    
}
   bool read_entrance()
{
    cin>>maze_name;
    if(maze_name=="END")
        return false;
    char dir0;
    cin>>r0>>c0>>dir0>>r2>>c2;
    dir=dir_id(dir0);
    r1=r0+dr[dir];//起点的dir和转向相互关联
    c1=c0+dr[dir];
    read();
    return true;
    
    
    
}
  int dir_id(char c)
  {
      return (strchr(dirs,c)-dirs);
  }
  int turn_id(char c)
  {
      return (strchr(turns,c)-turns);
  }
  const int dr[] = {-1, 0, 1, 0};  
  const int dc[] = {0, 1, 0, -1}; 
  struct Node
  {
    int r,c,dir;
  
  Node(int r=0,int c=0,int dir=0):r(r),c(c),dir(dir){}
  //c++构造器,进行初始化
  };
  int d[maxn][maxn][maxn];
  Node p[maxn][maxn][maxn];
  
  Node walk(const Node& u, int turn) {  
    int dir = u.dir;//改变朝向  
    if (turn == 1) dir = (dir + 3) % 4;  
    if (turn == 2) dir = (dir + 1) % 4;  
    //r + dr[dir], c + dc[dir]表示在(r, c)位置朝dir方向前进一格。  
    //所以向左转或向右转时,我们只要先改变朝向后再让原先的行r加上dr[dir]和列c加上dc[dir]就行了  
    return Node(u.r + dr[dir], u.c + dc[dir], dir);  
}  
void print_ans(Node u) {  
    //从目标结点逆序追溯到初始结点  
    vector<Node> nodes;  
    while (true) {  
        nodes.push_back(u);  
        if (d[u.r][u.c][u.dir] == 0) break;  
        u = p[u.r][u.c][u.dir];  
    }  
    nodes.push_back(Node(r0, c0, dir));  
    cout << maze_name << endl;  
    //打印解,每行10个  
    int cnt = 0;  
    for (int i = nodes.size() - 1; i >= 0; i--) {  
        if (cnt % 10 == 0) cout << " ";  
        cout << " (" << nodes[i].r << "," << nodes[i].c << ")";  
        if (++cnt % 10 == 0) cout << endl;  
    }  
    if (nodes.size() % 10 != 0) cout << endl;  
}  
  
  
  bool inside(int r,int c)
  {
      if(r>=1&&r<=9&&c>=1&&c<=9)
        return true;
      return false;
  }  
  
  
  void solve()
  {
   queue<Node> q;//泛型,此队列中只能存放Node类的对象
   memset(d,-1,sizeof(d));
   Node n1(r1,c1,dir1);
   q.push(n1);
   d[r1][c1][dir1]=0;
   while(!q.empty())
   {
       Node u = q.front(); q.pop();  
        if (u.r == r2 && u.c == c2) {  
            print_ans(u);  
            return;  
        }  
        for (int i = 0; i < 3; i++) {  
            Node v = walk(u, i);  
            if (has_edge[u.r][u.c][u.dir][i] && inside(v.r, v.c)  
                && d[v.r][v.c][v.dir] < 0) {  
                d[v.r][v.c][v.dir] = d[u.r][u.c][u.dir] + 1;  
                p[v.r][v.c][v.dir] = u;  
                q.push(v);  
            }  
        }  
    }  
    cout << maze_name << endl;  
    cout << "  No Solution Possible" << endl; 
   
  }
  
  int main()
  {
      while(read_entrance())
      {
          sovle();
      }
      return 0;
  }
  


































  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值