UVA - 816 Abbott's Revenge (BFS求最短路并打印路径)

版权声明:编写不易,转载请注明出处,谢谢。 https://blog.csdn.net/qingshui23/article/details/82973433

The 1999 World Finals Contest included a problem based on a dice maze. At the time the problem
was written, the judges were unable to discover the original source of the dice maze concept. Shortly
after the contest, however, Mr. Robert Abbott, the creator of numerous mazes and an author on the
subject, contacted the contest judges and identified himself as the originator of dice mazes. We regret
that we did not credit Mr. Abbott for his original concept in last years problem statement. But we are
happy to report that Mr. Abbott has offered his expertise to this years contest with his original and
unpublished walk-through arrow mazes.
As are most mazes, a walk-through arrow maze is traversed by moving from intersection to intersection
until the goal intersection is reached. As each intersection is approached from a given direction,
a sign near the entry to the intersection indicates in which directions the intersection can be exited.
These directions are always left, forward or right, or any combination of these.
Figure 1 illustrates a walk-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 go only forward. Continuing forward takes you toward (1,1). The sign at (1,1) as you approach from
the south indicates that you may exit (1,1) only by making 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 is also 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 have the option of continuing straight or turning left. Continuing straight would take
you on toward (1,1), while turning left would take you south to (2,2). The actual (unique) solution to
this maze is the following sequence 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 program to solve valid walk-through arrow mazes. Solving a maze means (if
possible) finding a route through the maze that leaves the Entrance in the prescribed direction, and
ends in the Goal. This route should not be longer than necessary, of course

题目大意:
有一个最多包含 9 9 9*9 个交叉点的迷宫,刚进入交叉点时会有一个朝向 N E S W NESW ,然后根据这个朝向又会有三个走向 F L R FLR ,然后输入起点、离开起点时的朝向和终点,求一条最短路,输出最短路径。

解题思路:
一看到最短路径,那么显然去想 B F S BFS 搜索,那么这个题也是一样的,但是怎么搜呢?首先我们定义一个结构体,结构体的内容是这个点的横纵坐标和进入这个点时的朝向,是一个三元组 ( x , y , t r ) (x,y,tr) ,那么我们根据这个三元组去找他的后继状态,他的后继状态肯定是跟朝向有关系的,而且跟进入这个点时的走向也是有关系的,找到后继时将其放入队列,但是这个题目还需要打印路径,那么我们只需要在放入队列的时候记录一下当前节点的父亲节点即可,然后倒序打印就ok了,这个看一下代码就很清楚了。需要注意的是很多的细节问题,初始状态并不是题目中给定的初始位置,因为他只有一个走向,所以并不能当做初始状态,其他的就需要注意细节问题就OK啦。
这个题目其实看着挺麻烦的,其实代码都是模块化的,思路也挺清晰的,是一个挺不错的题目。

吐槽:
在输出的时候,需要在行首输出两个空格,就因为这个问题WA了好多发,浪费了很多时间,好气哟!!!!!

代码如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 1e9;
const string dir="NESW";//上右左下
const string turn="FLR";
struct Node
{
    int x, y, tr;
    Node(){}
    Node(int xx, int yy, int trr)
    {
        x = xx; y = yy; tr = trr;
    }
}S, pa[20][20][4];
int dis[20][20][4];
int sx, sy, st, ex, ey;
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
bool hasEdge[20][20][4][4];
vector<Node> vec;
Node nxtNode(Node u, int i)
{
    int t = u.tr;
    if(i == 1)  t = (t+3)%4;//向左走
    if(i == 2)  t = (t+1)%4;//向右走
    return Node(u.x+dx[t], u.y+dy[t], t);
}
bool check(Node u)
{
    if(u.x<1||u.x>9||u.y<1||u.y>9) return false;
    if(dis[u.x][u.y][u.tr] != INF) return false;
    return true;
}
bool readCase()
{
    string s; cin>>s;
    if(s == "END") return false;
    cout<<s<<endl;
    cin>>sx>>sy>>s>>ex>>ey;
    st = dir.find(s);
    S = Node(sx, sy, st);
    sx+=dx[st];
    sy+=dy[st];
    while(1)
    {
        int x, y; cin>>x;
        if(x == 0) break;
        cin>>y;
        while(1)
        {
            cin>>s;
            if(s == "*") break;
            for(int i=1; i<s.length(); i++)
                hasEdge[x][y][dir.find(s[0])][turn.find(s[i])] = true;
        }
    }
    return true;
}
void print(Node root)
{
    while(1)
    {
        vec.push_back(root);
        if(dis[root.x][root.y][root.tr] == 0) break;
        root = pa[root.x][root.y][root.tr];
    }
    vec.push_back(S);
    reverse(vec.begin(), vec.end());
    for(int i=0; i<vec.size(); i++)
    {
        if(i%10 == 0) cout<<" ";
        cout<<" ("<<vec[i].x<<","<<vec[i].y<<")";
        if(i%10 == 9) cout<<endl;
    }
    if(vec.size()%10) cout<<endl;
}
void bfs()
{
    queue<Node> q;
    Node t(sx, sy, st);
    dis[sx][sy][st] = 0;
    //cout<<sx<<" "<<sy<<" "<<st<<endl;
    q.push(t);
    while(!q.empty())
    {
        t = q.front(); q.pop();
        if(t.x==ex && t.y==ey)
        {
            print(t);
            return ;
        }
        for(int i=0; i<3; i++)
        {
            Node nxt = nxtNode(t, i);
            if(check(nxt) && hasEdge[t.x][t.y][t.tr][i])
            {
                dis[nxt.x][nxt.y][nxt.tr] = dis[t.x][t.y][t.tr]+1;
                pa[nxt.x][nxt.y][nxt.tr] = t;
                q.push(nxt);
            }
        }
    }
    cout<<"  No Solution Possible\n";//一定要注意是两个空格
}
void Init()
{
    for(int i=0; i<20; i++) for(int j=0; j<20; j++) for(int k=0; k<4; k++) dis[i][j][k] = INF;
    memset(hasEdge, false, sizeof hasEdge);
    vec.clear();
}
int main()
{
    while(1)
    {
        Init();
        if(readCase()) bfs();
        else break;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qingshui23/article/details/82973433
816
816
今日推荐