zoukankan      html  css  js  c++  java
  • UVA816 Abbott's Revenge (三元组BFS)

    题目描述:

    输入输出:

    输入样例:

    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
    思路:
    将普通图(只含有两个方向的平面图)改为三元组表示的图,再在“平面图”的基础上调用BFS算法,求单元最短路径。输入输出很繁(对我这个菜鸡来说)。
    还有就是行走函数根据转向不同将char类型的方向映射到两个一维的int上去的方式很巧妙(巧妙的加3加1取余4,就打乱原来的NESW逆时针顺序),
    再通过dr,dc数组实现方向的变化和移动。
    注意初始位置(r1,c1)不是原始位置(r0,c0)。
    开始将d数组初始化为-1,到d[r1][c1][dir]就为0(加了1)。所以在用vector反着打印路径时最后加一个(r0,c0)(未存)

    代码:(有详细的但也难懂的注释)
      1 #include <cstdio>
      2 #include <iostream>
      3 #include <cstring>
      4 #include <vector>
      5 #include <queue>
      6 #define max_n 10
      7 using namespace std;
      8 struct Node
      9 {
     10     int r;
     11     int c;
     12     int dir;
     13     Node(int r1=0,int c1=0,int d1=0) :r(r1),c(c1),dir(d1) {}
     14     //构造Node,带有默认参数,不然会在Node p[][][]那里报错,认为这个语句是在构造Node
     15 };
     16 int d[max_n][max_n][4];//表示初始状态到(r,c,dir)的最短路长度
     17 Node p[max_n][max_n][4];//保存了状态(r,c,dir)在BFS数中的父结点
     18 int has_edge[max_n][max_n][4][3];//当前状态是(r,c,dir),是否可以沿着转弯方向turn行走
     19 
     20 //行走
     21 const char* dirs = "NESW"; //顺时针旋转的顺序
     22 const char* turns = "FLR";
     23 int dir_id(char c) {return strchr(dirs,c)-dirs;} //将char类型的dir转化为dirs中相应的所在位置
     24 int turn_id(char c) {return strchr(turns,c)-turns;}//将char类型的turn在turns中找到对应的元素位置
     25 const int dr[] = {-1,0,1,0};//用上面找到的元素位置来确定当前行行走方向
     26 const int dc[] = {0,1,0,-1};//用上面找到的元素位置来确定当前列行走方向
     27 char maze[21];//迷宫名称
     28 int r0,c0,dir;//原始位置和方向
     29 int r1,c1;//初始位置和方向
     30 int r2,c2;//目标位置
     31 //巧妙的行走函数和对应关系
     32 //dirs 0N 1E 2S 3W
     33 //顺时针
     34 //dir' 3  0  1  2
     35 //逆时针
     36 //dir' 1  2  3  0
     37 //dr  -1  0  1  0
     38 //dc   0  1  0 -1
     39 Node walk(const Node& u,int turn)
     40 {
     41     int dir = u.dir;
     42     if(turn==1) dir = (dir+3)%4;
     43     if(turn==2) dir = (dir+1)%4;
     44     return Node(u.r+dr[dir],u.c+dc[dir],dir);
     45 }
     46 //判断越界函数
     47 int inside(int r,int c)
     48 {
     49     return 0<r&&r<=9&&0<c&&c<=9;
     50 }
     51 //输出函数
     52 //要求:
     53 //第一行输出迷宫名
     54 //后几行输出路径,且除最后一行外,其他每行都是空两格+10个(r,c)形式空格分隔的坐标
     55 void printa(Node u)
     56 {
     57     vector<Node> nodes;//可用递归方式打印,但可能溢栈,可改用循环,用vector存储
     58     for(;;)
     59     {
     60         nodes.push_back(u);
     61         if(d[u.r][u.c][u.dir]==0) break;
     62         u = p[u.r][u.c][u.dir];
     63     }
     64     nodes.push_back(Node(r0,c0,dir));
     65 
     66     int cnt = 0;
     67     for(int i = nodes.size()-1;i>=0;i--)
     68     {
     69         if(cnt%10==0) //值得品味的细节1
     70         {
     71             printf(" ");
     72         }
     73         printf(" (%d,%d)",nodes[i].r,nodes[i].c);
     74         if(++cnt%10==0)//值得品味的细节2
     75         {
     76             printf("
    ");
     77         }
     78     }
     79     if(nodes.size()%10!=0)
     80     {
     81         printf("
    ");
     82     }
     83 }
     84 //输入函数
     85 //先读入迷宫名,若为END返回0,
     86 //然后一行读入起点r,c,dir,终点r,c
     87 //然后处理交叉处的方向改变,将这些信息用数组has_edge[r][c][dir][turn]记录下来,为以后BFS提供基础
     88 //读到*结束小循环,读到0结束大循环
     89 int read()
     90 {
     91     cin >> maze;
     92     if(maze[0]=='E'&&maze[1]=='N'&&maze[2]=='D'&&strlen(maze)==3) return 0;
     93     cout << maze << endl;
     94     memset(maze,0,sizeof(maze[0]));
     95 
     96     char dirs;
     97     cin >> r0 >> c0 >> dirs >> r2 >> c2;
     98     dir = dir_id(dirs);
     99     r1 = r0+dr[dir];
    100     c1 = c0+dc[dir];
    101     memset(has_edge,0,sizeof(has_edge));
    102 
    103     for(;;)
    104     {
    105         int r,c;
    106         cin >> r;
    107         if(r==0)
    108         {
    109             break;
    110         }
    111         cin >> c;
    112         char chr[99];
    113         while(cin >> chr)
    114         {
    115             if(chr[0]=='*')
    116             {
    117                 break;
    118             }
    119             for(int i = 1;i<strlen(chr);i++)
    120             {
    121                 has_edge[r][c][dir_id(chr[0])][turn_id(chr[i])] = 1;
    122             }
    123             //cout << r << " " << c << " " << chr << endl;
    124             memset(chr,0,sizeof(chr[0]));
    125         }
    126     }
    127     return true;
    128 }
    129 //BFS主过程
    130 void solve()
    131 {
    132     queue<Node>q;
    133     memset(d,-1,sizeof(d));
    134     Node u(r1,c1,dir);
    135     d[u.r][u.c][u.dir] = 0;
    136     q.push(u);
    137     while(!q.empty())
    138     {
    139         Node u = q.front();q.pop();
    140         if(u.r==r2&&u.c==c2)
    141         {
    142             printa(u);
    143             return;
    144         }
    145         for(int i = 0;i<3;i++)
    146         {
    147             Node v = walk(u,i);
    148             if(has_edge[u.r][u.c][u.dir][i]&&inside(v.r,v.c)&&d[v.r][v.c][v.dir]<0)
    149             {
    150                 d[v.r][v.c][v.dir] = d[u.r][u.c][u.dir] +1;
    151                 p[v.r][v.c][v.dir] = u;
    152                 q.push(v);
    153             }
    154 
    155         }
    156     }
    157     printf("  No Solution Possible
    ");
    158 }
    159 int main()
    160 {
    161     while(read())
    162     solve();
    163     return 0;
    164 }
  • 相关阅读:
    前端工程师必备:前端的模块化
    1414. 和为 K 的最少斐波那契数字数目(贪心)
    62. 不同路径(经典dp问题简单路径)
    1051. 高度检查器(排序比较)
    1144. 递减元素使数组呈锯齿状(两次扫)
    面试题 16.04. 井字游戏(模拟即可)
    微信小程序 base64ToArrayBuffer
    人人商城手机端添加控制器
    微擎自定义回复规则
    JS 对浏览器相关的操作
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11229296.html
Copyright © 2011-2022 走看看