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 }
  • 相关阅读:
    learnyou 相关网站
    hdu 3038 How Many Answers Are Wrong
    hdu 3047 Zjnu Stadium 并查集高级应用
    poj 1703 Find them, Catch them
    poj 1182 食物链 (带关系的并查集)
    hdu 1233 还是畅通工程
    hdu 1325 Is It A Tree?
    hdu 1856 More is better
    hdu 1272 小希的迷宫
    POJ – 2524 Ubiquitous Religions
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11229296.html
Copyright © 2011-2022 走看看