题目:有一个最多包含9*9个交叉点的迷宫。输入起点、离开起点时的朝向和终点,求一条最短路(多解时任意输出一个即可)。

这个迷宫的特殊之处在于:进入一个交叉点的方向(用NEWS这4个字母分别表示北东西南,即上右左下)不同,允许出去的方向也不同。例如,12WLFNRER*表示交叉点(1, 2)(上数第1行,左数第2列)有3个路标(字符“*" 只是结束标志), 如果进入该交叉点时的朝向为W(即朝左), 则可以左转(L)或者直行(F); 如果进入时朝向为N或者E则只能右转(R),如下图:

 

分析:此题直接做的话,略微有些困难,会BFS求最短路的知识铺垫会更容易理解一些,放上链接:BFS求最短路  了解的直接跳过。。。

这道题与普通的求最短路的题目的区别是每一个结点有各自的转向限制,因此在声明结构体的时候需要增加进入结点时的方向,则每个结点为(r,c,dir),这样通过进入时的方向来判断可以往哪转向,而普通最短路四个方向都能转。另外初始状态是从入口朝着进入方向走一步之后的结点。其他思想与普通最短路一致,具体请参照代码,里边有注释。

 1 #include <iostream>
2 #include <cstdio>
3 #include <cmath>
4 #include <cstring>
5 #include <queue>
6 #include <vector>
7 using namespace std;
8 const int maxn = 10;
9 struct Node{
10 int r;
11 int c;
12 int dir;
13 Node(int r = 0,int c = 0,int dir = 0):r(r),c(c),dir(dir){}
14 };
15 int has_edg[maxn][maxn][4][3]; //每个结点的转向信息
16 int d[maxn][maxn][4]; //每个结点距离初始点的距离
17 Node pre[maxn][maxn][4];
18 int r0,c0,r1,c1,r2,c2,dir;
19 const char* dirs = "NESW"; //从上右下左四个方向进入(顺时针)
20 const char* turns = "FLR"; //直行、左拐、右拐四种转向
21 int dir_id(char d){ return strchr(dirs,d) - dirs;}
22 int turn_id(char t){ return strchr(turns,t) - dirs;}
23 int dr[4] = {-1,0,1,0}; //NESW四个方向
24 int dc[4] = {0,1,0,-1};
25 bool read_case(){
26 char s1[99],s2[99];
27 if(scanf("%d%d%s%d%d",&c0,&r0,s1,&r2,&c2) != 5) return false;
28
29 dir = dir_id(s1[0]); //从给出的起点走一步,获得起始位置
30 r1 = r0 + dr[dir];
31 c1 = c0 + dc[dir];
32
33 memset(has_edg,0,sizeof(has_edg));
34 for(;;){
35 int c,r;
36 cin >> c;
37 if(c == 0) break;
38 cin >> r;
39 while(scanf("%s",s2) == 1 && s2[0] != '*'){
40 for(int i = 1;i < strlen(s2);i++){
41 has_edg[c][r][dir_id(s2[0])][turn_id(s2[i])] = 1;
42 }
43 }
44 }
45 return true;
46 }
47 Node walk(const Node& n,int turn){ //向前走一步
48 int dir = n.dir; //turn == 0时直走,方向不变
49 if(turn == 1) dir = (dir + 3) % 4; //左转(从进入时的方向顺时针数三个方向)
50 if(turn == 2) dir = (dir + 1) % 4; //右转(从进入时的方向顺时针数一个方向)
51 return Node(n.r + dr[dir],n.c + dc[dir],dir);
52 }
53 bool inside(int r,int c){
54 return r >= 1 && r <= 9 && c >= 1 && c <= 9;
55 }
56
57 void print_ans(Node n){
58 vector<Node> nodes;
59 for(;;){
60 nodes.push_back(n);
61 if(d[n.r][n.c][n.dir] == 0) break;
62 n = pre[n.r][n.c][n.dir];
63 }
64 nodes.push_back(Node(r0,c0,dir));
65 int cnt = 0;
66 for(int i = nodes.size();i >= 0;i--){
67 cout << "(" << nodes[i].r << "," << nodes[i].c << ")" << " ";
68 cnt++;
69 if(cnt % 10 == 0) cout << "\n";
70 }
71 }
72 void solve(){
73 queue<Node> q;
74 memset(d,-1,sizeof(d));
75 q.push(Node(r1,c1,dir));
76 d[r1][c1][dir] = 0; //初始点距离为0
77 while(!q.empty()){
78 Node n = q.front(); q.pop();
79 if(n.r == r2 && n.c == c2){ print_ans(n); return;}
80 for(int i = 0;i < 3;i++){
81 if(has_edg[n.r][n.c][n.dir][i]){
82 Node v = walk(n,i);
83 if(inside(v.r,v.c) && d[v.r][v.c][v.dir] == -1){
84 d[v.r][v.c][v.dir] = d[n.r][n.c][n.dir] + 1;
85 pre[v.r][v.c][v.dir] = n;
86 q.push(v);
87 }
88 }
89 }
90 }
91 printf("No Solution Possible\n");
92 }
93 int main(){
94 while(read_case()){
95 solve();
96 }
97 return 0;
98 }

Abbott的复仇(Abbott's Revenge)的更多相关文章

  1. 算法入门经典第六章 例题6-14 Abbott的复仇(Abbott's Revenge)BFS算法实现

    Sample Input 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 SF ...

  2. UVA816 Abbott的复仇 Abbott's Revenge

    以此纪念一道用四天时间完结的题 敲了好几次代码的出错点:(以下均为正确做法) memset初始化 真正的出发位置必须找出. 转换东西南北的数组要从0开始. bfs没有初始化第一个d 是否到达要在刚刚取 ...

  3. 6_14 Abbott的复仇(UVa816)<图的最短路BFS>

    1999次世界总决赛的比赛包括一个骰子迷宫问题.在这个问题被写的时候,法官们无法发现骰子迷宫概念的原始来源.不久之后的比赛,但是,罗伯特先生雅培,无数的迷宫和对作者的创造者主题,联系大赛评委,自称是骰 ...

  4. uva 816 Abbott的复仇

    题目链接:https://uva.onlinejudge.org/external/8/816.pdf 紫书:P165 题意: 有一个最多包含9*9个交叉点的迷宫.输入起点.离开起点时的朝向和终点,求 ...

  5. UVa 816 Abbott的复仇(BFS)

    寒假的第一道题目,在放假回家颓废了两天后,今天终于开始刷题了.希望以后每天也能多刷几道题. 题意:这道BFS题还是有点复杂的,给一个最多9*9的迷宫,但是每个点都有不同的方向,每次进入该点的方向不同, ...

  6. 6-14 Abbott的复仇 uva816

    我的第一题bfs 将方向固定  NESW  然后左转和右转就是+3和+1!!! 还有就是  建立一个数组 储存父节点  这样就可以往回打印出路径   打印的截至条件是 d[][][]==0时  说明到 ...

  7. [uva816]AbbottsRevenge Abbott的复仇(经典迷宫BFS)

    这题思路就普通的BFS加上一个维度朝向,主要是要注意输入,输出,以及细节的处理 #include<cstdio> #include<cstring> #include<q ...

  8. Uva 816 Abbott的复仇(三元组BFS + 路径还原)

    题意: 有一个最多9*9个点的迷宫, 给定起点坐标(r0,c0)和终点坐标(rf,cf), 求出最短路径并输出. 分析: 因为多了朝向这个元素, 所以我们bfs的队列元素就是一个三元组(r,c,dir ...

  9. 利用BFS实现最短路

    首先,我们要知道BFS的思想,BFS全称是Breadth-First-Search. 二叉树的BFS:通过BFS访问,它们的访问顺序是它们到根节点距离从小到大的排序. 图的BFS:同样的,离起点越近, ...

随机推荐

  1. 用算法去扫雷(go语言)

    最初的准备 首先得完成数据的录入,及从扫雷的程序读取界面数据成为我的算法可识别的数据 其次是设计扫雷的算法,及如何才能判断格子是雷或者可以点击鼠标左键和中键. 然后将步骤2的到的结果通过我的程序实现鼠 ...

  2. 正式班D9

    2020.10.16星期五 正式班D9 一.vmware workstation的使用 虚拟机管理软件 定义 虚拟机(Virtual Machine)软件是一套特殊的软件,它可以作为操作系统独立运行, ...

  3. harbor搭建与使用

        前两天测试服务docker化并k8s布署时,出于方便,使用了docker hub.由于我们的代码是要放到镜像里的,通过运行容器,便能获取我们的全部代码,风险很大.所以我们决定进行私有化的镜像部 ...

  4. spring boot:thymeleaf给fragment传递参数的方法(spring boot 2.3.3)

    一,thymeleaf如何给fragment传递参数? 1,如果是全局的参数,可以用interceptor中传递 非全局参数,可以从controller中传递 2,引用片断时也可以传递参数 说明:刘宏 ...

  5. centos8安装fastdfs6.06集群方式三之:storage的安装/配置/运行

    一,查看本地centos的版本 [root@localhost lib]# cat /etc/redhat-release CentOS Linux release 8.1.1911 (Core) 说 ...

  6. Linux标准重定向-输入-输出-错误-多重

    一切皆文件,都是文件的操作 三种I/O设备 标准的输入输出 程序:指令+数据 读入数据:Input 输出数据:Output 系统中打开一个文件系统自动分配文件描述符,除了0,1,2是固定的,其他的都是 ...

  7. Mybatis原理之数据源和连接池

    在Java工程项目中,我们常会用到Mybatis框架对数据库中的数据进行增删查改,其原理就是对 JDBC 做了一层封装,并优化数据源的连接. 我们先来回顾下 JDBC 操作数据库的过程. JDBC 操 ...

  8. Redis 入门与 ASP.NET Core 缓存

    目录 基础 Redis 库 连接 Redis 能用 redis 干啥 Redis 数据库存储 字符串 订阅发布 RedisValue ASP.NET Core 缓存与分布式缓存 内存中的缓存 ASP. ...

  9. Camera2使用textureView支持

    SurfaceView 绘制会有独立窗口, TextureView 没有独立的窗口,可以像普通的 View 一样,更高效更方便 public class MainActivity extends Ap ...

  10. Chrome FeHelper 插件下载地址

    方便大家下载 下载可用,本人亲自测试 下载地址: 地址链接