• UVA 816 -- Abbott's Revenge(BFS求最短路)


     UVA 816 -- Abbott's Revenge(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树中的父结点。

           规律:: 很多复杂的迷宫问题都可以转化成最短路问题, 然后用BFS求解。 在套用BFS框架之前, 需要先搞清楚图中的“结点”包含哪些内容。

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<vector>
      5 #include<queue>
      6 using namespace std;
      7 int r0,c0,r2,c2,r1,c1,dir;
      8 const char *dirs = "NESW";
      9 const char *turns = "FLR";
     10 const int dr[] = {-1,0,1,0};
     11 const int dc[] = {0,1,0,-1};
     12 const int maxn = 10;
     13 int dir_id(char s){return strchr(dirs,s) - dirs;}
     14 int turn_id(char s){return strchr(turns,s) - turns;}
     15 int has_edge[maxn][maxn][4][3];// 表示当前状态(r,c,dir),是否可以沿着转弯方向[trun]行走。
     16 struct Node{
     17     int r,c,dir;
     18     Node(int r=0,int c=0,int dir=0):r(r),c(c),dir(dir) {}
     19 };
     20 int d[maxn][maxn][4];///表示初始状态到(r,c,dir)的最短路径长度
     21 Node p[maxn][maxn][4];///用来记录从哪一步走到(r,c,dir),即其父节点
     22 ///读入地图
     23 bool read_input()
     24 {
     25     char s[99],s2[99];
     26     if(scanf("%s%d%d%s%d%d",s,&r0,&c0,s2,&r2,&c2) != 6) return false;
     27     cout<<s<<endl;
     28     dir = dir_id(s2[0]);
     29     r1 = r0 + dr[dir];
     30     c1 = c0 + dc[dir];
     31     memset(has_edge,0,sizeof(has_edge));
     32     for(;;)
     33     {
     34         int r,c;
     35         cin>>r;
     36         if( r == 0) break;
     37         cin>>c;
     38         while(cin>>s && s[0] != '*')
     39         {
     40             for(int i=1;i<strlen(s);i++)///将当前路口(r,c),可以的前进方向存到has_edge中
     41                 has_edge[r][c][dir_id(s[0])][turn_id(s[i])] = 1;
     42         }
     43     }
     44     return true;
     45 }
     46 ///从当前节点u,转向为i,前进一步
     47 Node walk(Node u,int i)
     48 {
     49     int temp = u.dir;
     50     if(i == 1) temp = (temp+3)%4;///逆时针旋转,L
     51     if(i == 2) temp = (temp+1)%4;///顺时针旋转,R
     52     return Node(u.r + dr[temp],u.c + dc[temp],temp);
     53 }
     54 ///判断是否出界
     55 bool inside(int r,int c)
     56 {
     57     return r >= 1 && r <= 9 && c >= 1 && c <= 9;
     58 }
     59 ///将结果进行打印
     60 void print_ans(Node u)
     61 {
     62     vector<Node> nodes;
     63     for(;;)
     64     {
     65         nodes.push_back(u);
     66         if(d[u.r][u.c][u.dir] == 0) break;
     67         u = p[u.r][u.c][u.dir];
     68     }
     69     nodes.push_back(Node(r0,c0,dir));
     70     ///打印解,每行10个
     71     int cnt = 0;
     72     for(int i=nodes.size()-1;i>=0;i--)
     73     {
     74         if(cnt % 10 == 0) printf(" ");
     75         printf(" (%d,%d)",nodes[i].r,nodes[i].c);
     76         if(++cnt % 10 == 0) cout<<endl;
     77     }
     78     if(nodes.size() % 10 != 0) cout<<endl;
     79 }
     80 ///BFS
     81 void solve()
     82 {
     83     queue<Node> q;
     84     memset(d,-1,sizeof(d));
     85     Node u(r1,c1,dir);
     86     d[u.r][u.c][u.dir] = 0;
     87     q.push(u);
     88     while(!q.empty())
     89     {
     90         Node u = q.front();q.pop();
     91         if(u.r == r2 && u.c == c2) {print_ans(u);return;}///到达终点
     92         for(int i=0;i<3;i++)///3个方向,0-F,1-L,2-R
     93         {
     94             Node v = walk(u,i);//超当前方向走,下一个结点
     95             if(has_edge[u.r][u.c][u.dir][i] ///1.判断是否能向当前方向走
     96                && inside(v.r,v.c)///2.判断是否出界
     97                && d[v.r][v.c][v.dir] < 0)///3.判断是否已经走过这条路 u->v
     98             {
     99                 d[v.r][v.c][v.dir] = d[u.r][u.c][u.dir]+1;
    100                 p[v.r][v.c][v.dir] = u;//记录父节点
    101                 q.push(v);
    102             }
    103         }
    104     }
    105     cout<<"  No Solution Possible"<<endl;//走了所有可以走的可能, 无法到达终点
    106 }
    107 int main()
    108 {
    109     while(read_input())
    110     {
    111         solve();
    112     }
    113 
    114     return 0;
    115 }

  • 相关阅读:
    socket 编程
    空间配置器
    线程
    Linux系统编程——进程替换:exec 函数族
    linux粘着位
    exit函数与_exit
    [smart210] 定时器与PWM
    [smart210] s5pv210的中断体系
    [smart210] Nand Flash K9F4G08U0B 的配置与读写控制(二)
    [smart210] Nand Flash K9F4G08U0B 的配置与读写控制(一)
  • 原文地址:https://www.cnblogs.com/yxh-amysear/p/8453164.html
Copyright © 2020-2023  润新知