uva_816 Abbott's Revenge(BFS求解最短路、结点状态由坐标和方向表示)

有点难以置信,写得最久的一道题竟然一遍AC。

分析:

  1. 这是给定起点、终点的图的最短路问题。并且并无特殊之处,首选BFS。

  2. 唯一的特殊之处在于图中结点并非简单地由坐标构成,还有方向。因此,结点(或者说状态)为三元组:(r, c, direction);

  3. 图主要有两种存储方式:邻接表和邻接矩阵。这种显式的、迷宫型的图,首选邻接矩阵。

    用bool has_edge[r][c][dir][turn]存储结点之间的关系,含义为:结点(r, c, dir)是否能以turn这种拐弯方式到达另一个结点。

    (当然也可以用邻接表 vector<Node> next_node[r][c][dir])  //等等....貌似这不是邻接表,邻接表存储的是边...

  4. 标记结点访问情况的三维数组 bool vis[r][c][dir]。注意:如果题目需要路径长度的情况,可以用int d[r][c][dir],当其为-1时标识不可达。

  5. 如何根据当前的dir和turn给出下一步的方向。当然可以依次判断。但是,要记住一个原则:将实际含义抽象化、数字化,并找到其中的规律,从而找到简单的表示方式。

  

char *dirs = "NESW";
char *turns = "FLR";
int ID_dir(char c){return strchr(dirs, c) - dirs;}
int ID_turn(char c){return strchr(turns, c) - turns;}
int dr[] = {-1, 0, 1, 0};   //与dirs = "NESW"的顺序一致,即顺时针。
int dc[] = {0, 1, 0, -1};

int getDir(int turn, int dir)
{
    if(turn == 0) return dir;
    if(turn == 1){
        return (dir + 3)%4;
    }
    if(turn == 2
){ return (dir + 1)%4; } }

 

  

#include<bits/stdc++.h>
using namespace std;

const int maxn = 9 + 3;
const int maxs = 20 + 3;


string kase;
char *dirs = "NESW";
char *turns = "FLR";
int ID_dir(char c){return strchr(dirs, c) - dirs;}
int ID_turn(char c){return strchr(turns, c) - turns;}
int dr[] = {-1, 0, 1, 0};   //与dirs = "NESW"的顺序一致,即顺时针。
int dc[] = {0, 1, 0, -1};

int getDir(int turn, int dir)
{
    if(turn == 0) return dir;
    if(turn == 1){
        return (dir + 3)%4;
    }
    if(turn == 2){
        return (dir + 1)%4;
    }
}

struct Node{
    int r, c;
    int direction;
    Node(int r = 0, int c = 0, int dir = 0):r(r), c(c), direction(dir){}
};

bool inside(const Node& node, int dir)
{
    int rr = node.r + dr[dir];
    int cc = node.c + dc[dir];
    return rr >= 0 && rr <= 9 && cc >= 0 && cc <= 9;
}

Node walk(const Node& node, int dir)
{
    int rr = node.r + dr[dir];
    int cc = node.c + dc[dir];
    return Node(rr, cc, dir);
}
Node entrance, goal;
Node node0;


/*
node state:  (coordinate, direction)
            bool has_edge[r][c][dir][turn] represents whether it's valid to turn with certain turning when on (r, c)
 */

//int d[maxn][maxn][4];
bool has_edge[maxn][maxn][4][3];    //or the structure of the graph is matrix, has_edge is actually describe the graph.

void readData()
{
    while(true){
        int r, c;
        string t;
        cin >> r;
        if(r == 0) return;
        cin >> c;
        while(cin >> t){
            if(t == "*"){
                break;
            }
            int dir = ID_dir(t[0]);
            for(int i = 1; i < t.size(); i++){
                has_edge[r][c][dir][ID_turn(t[i])] = true;
            }
        }
    }
}
Node p[maxn][maxn][4];
bool vis[maxn][maxn][4];

void print_ans(Node u)
{
    vector<Node>ans;
    while(1){
        ans.push_back(u);
        u = p[u.r][u.c][u.direction];
        if(u.r == 0){
            break;
        }
    }
    cout << kase << endl << "  ";
    ans.push_back(entrance);
    for(int i = ans.size() - 1, cnt = 1; i >= 0; i--, cnt++){
        printf("(%d,%d)", ans[i].r, ans[i].c);
        if(i == 0){
            cout << endl;
            return ;
        }
        if(cnt % 10 == 0){
          cout << endl << "  ";
        }
        else cout << " ";
    }
}


void solve()
{
    queue<Node>q;
    q.push(node0);
    p[node0.r][node0.c][node0.direction] = Node();
    while(!q.empty()){
        Node u = q.front(); q.pop();
        if(u.r == goal.r && u.c == goal.c){
            print_ans(u);
            return;
        }
        for(int i = 0; i < 3; i++){//try 3 probable turning
            int dir = getDir(i, u.direction);
            if(inside(u, dir) && has_edge[u.r][u.c][u.direction][i]){
                Node v = walk(u, dir);
                if(vis[v.r][v.c][v.direction]){
                   continue;
                }
                p[v.r][v.c][v.direction] = u;
                vis[v.r][v.c][v.direction] = true;
                q.push(v);
            }
        }
    }
    cout << kase << endl << "  ";
    cout << "No Solution Possible" << endl;
}


int main()
{

    while(cin >> kase && kase != "END"){
        string t;
        cin >> entrance.r >> entrance.c >> t >> goal.r >> goal.c;
        node0 = walk(entrance, ID_dir(t[0]));
        memset(has_edge, 0, sizeof(has_edge));  //
        memset(vis, 0, sizeof(vis));
        readData();
        solve();
    }
    return 0;
}

 

posted on 2019-02-25 18:26  nbsanshi  阅读(138)  评论(0编辑  收藏  举报

导航