Abbott's Revenge UVA 816(图 BFS)

题目大意:

有一个 9 * 9 的交叉点的迷宫。 输入起点, 离开起点时的朝向和终点, 求最短路(多解时任意一个输出即可)。进入一个交叉点的方向(用NEWS表示不同方向)不同时, 允许出去的方向也不相同。 例如:1 2 WLF NR ER * 表示如果 进去时朝W(左), 可以 左转(L)或直行(F), 如果 朝N只能右转(R) 如果朝E也只能右转。* 表示这个点的描述结束啦!

    输入有: 起点的坐标, 朝向, 终点的坐标。然后是各个坐标,和各个坐标点的情况(进去方向和可以出去的方向) 以*号表示各个坐标点描述的结束。

本题和普通的迷宫在本质上是一样的, 但是由于“朝向”也起了关键的作用, 所以需要一个三元组(r,c, dir)表示位于(r, c)面朝dir 的状态。 假设入口位置为(r0,c0)朝向为dir , 则初始状态并不是(r0, c0, dir), 而是(r1, c1, dir)因为开始时他别无选择, 只有一个规定的方向。 其中, (r1, c1)是沿着方向dir走一步之后的坐标, dir刚好是他进入该点时的朝向。    此处用d[r][c][dir]表示初始状态到(r, c, dir)的最短路长度, 并且用 p[r][c][dir]保存了状态(r, c, dir)在BFS树中的父结点


输入:第一行输入迷宫的名字,第二行迷宫的初始位置、方向以及终点位置,接下来每行输入迷宫中 每个点的状态(进入时方向+在该方向下该转向那些方向);以0结束一组数据。


  1. #include<cstdio>
  2. #include<queue>
  3. #include<vector>
  4. #include<cstring>
  5. using namespace std;
  6. const int maxn=10;
  7. struct note{
  8.     int r,c,dir;
  9.     note(int r1=0,int c1=0,int dir1=0):r(r1),c(c1),dir(dir1){}
  10.     };
  11. const char * dirs="NESW";            //顺时针旋转 
  12. const char * turns="FLR";            //旋转方向 
  13. int turn_id(char ch){return strchr(turns,ch)-turns;}
  14. int dir_id(char ch){return strchr(dirs,ch)-dirs;}

  15. int has_edge[maxn][maxn][4][3];             //当前状态(r,c,dir)是否可以沿着转弯方向走(turn)
  16. int d[maxn][maxn][4];              //初始状态到(r,c,dir)的最短路径 
  17. note path[maxn][maxn][4];   //保存路径 
  18. int r0,c0,dir,r1,c1,r2,c2;       //(r0,c0,dir0)初始状态,(r2,c2)最终状态 
  19. const int dr[][2]={{-1,0},{0,1},{1,0},{0,-1}};                 //向NESW(顺时针)方向移动时的坐标变化
  20. bool read(){
  21.     char s[20];scanf("%s",s);
  22.     if(!strcmp(s,"END"))return false;
  23.     printf("%s\n",s);
  24.      scanf("%d%d%s%d%d",&r0,&c0,s,&r2,&c2);
  25. //假设入口位置为(r0,c0),方向为dir,则初始状态并不是(r0,c0,dir),而是(r1,c1,dir),其中(r1,c1)是(r0,c0)沿着dir走一步之后的坐标(理解这一点很重要)
  26.      dir=dir_id(s[0]);
  27.      r1=r0+dr[dir][0];
  28.      c1=c0+dr[dir][1];

  29.      memset(has_edge,0,sizeof(has_edge));
  30.      while(true){
  31.          int r,c;
  32.          char s1[5];
  33.          scanf("%d",&r);
  34.          if(r==0)break;
  35.          scanf("%d",&c);
  36.          while(scanf("%s",s1)==1 && s1[0]!='*'){
  37.              for(int i=1;i<strlen(s1);i++)
  38.              has_edge[r][c][dir_id(s1[0])][turn_id(s1[i])]=1;
  39.          }
  40.      }
  41.      return true;
  42. }

  43. void print(note u){
  44.     vector<note>vec;
  45.     while(true){
  46.         vec.push_back(u);
  47.         if(d[u.r][u.c][u.dir]==1)break;
  48.          u=path[u.r][u.c][u.dir];
  49.         }
  50. vec.push_back(note(r0,c0,dir));
  51.         int count=0;
  52.         for(int i=vec.size()-1;i>=0;i--){
  53.             if(count%10==0&& count )printf("\n");
  54.             if(count%10==0 )printf("  (%d,%d)",vec[i].r,vec[i].c);
  55.             else printf(" (%d,%d)",vec[i].r,vec[i].c);
  56.             count++;
  57.         }
  58.         printf("\n");
  59. }

  60. note walk(const note &u,int turn){
  61.     int dir=u.dir;
  62.     if(turn == 1)dir=(dir+3)%4;           //逆时针 
  63.     if(turn == 2)dir=(dir+1)%4;           //顺时针 
  64.     return note(u.r+dr[dir][0],u.c+dr[dir][1],dir);
  65. }
  66. //接下来就是BFS的框架了
  67. void solve(){
  68.     queue<note>q;
  69.     memset(d,0,sizeof(d));
  70.     q.push(note(r1,c1,dir));
  71.     d[r1][c1][dir]=1;
  72.     while(!q.empty()){
  73.         note u=q.front();q.pop();
  74.         if(u.r==r2 && u.c== c2){
  75.             print(u);
  76.             return ;
  77.         }
  78.         for(int i=0;i<3;i++){
  79.             note v=walk(u,i);
  80.             if(has_edge[u.r][u.c][u.dir][i] && d[v.r][v.c][v.dir]==0){
  81.                 d[v.r][v.c][v.dir]=d[u.r][u.c][u.dir]+1;
  82.                 path[v.r][v.c][v.dir]=u;
  83.                 q.push(v);
  84.             }
  85.         }
  86.     }
  87.     printf("  No Solution Possible\n");
  88. }
  89. int main(){
  90.     while(read()){
  91.         solve();
  92.     }    
  93.     return 0;
  94. }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柏油

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值