题目:有一个最多包含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. docker启动服务---------------mysql

    1.查找镜像: docker search mysql 也可以去官网查看镜像tag,选择自己需要的版本,否则会下载最新版本:https://hub.docker.com/_/mysql/ 2.下载镜像 ...

  2. Java9系列第7篇:Java.util.Optional优化与增强

    我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 ...

  3. Helium文档14-WebUI自动化-hover鼠标悬浮

    前言 hover 实现功能是将鼠标光标悬停在给定的元素或点上 入参介绍 element def hover(element): """ :param element: T ...

  4. Java网关服务-AIO(一)

    Java网关-AIO(一) aio:声明一个byteBuffer,异步读,读完了之后回调,相比于Future.get(),可以减少阻塞.减少线程等待,充分利用有限的线程 nio:声明一个byteBuf ...

  5. for循环使用体会

    最近在看源码的时候看到了以下代码: Class[] var2 = componentClasses; int var3 = componentClasses.length; for(int var4 ...

  6. SpringMVC中ModelAndView的两个jar包引起的思考servlet和portlet

    在使用ModelAndView时,需要去导包,但是有两个包. 检查前台form表单提交的也正确,后台这也没有问题. 后来发现竟然时导包导错误了. 到此,如果是因为到错包问题,应该就解决了. 但是,深入 ...

  7. 单例模式的几种实现And反射对其的破坏

    一 单例模式概述 (一) 什么是单例模式 单例模式属于创建型模式之一,它提供了一种创建对象的最佳方式 在软件工程中,创建型模式是处理对象创建的设计模式,试图根据实际情况使用合适的方式创建对象.基本的对 ...

  8. C# NModbus RTU通信实现

    Modbus协议时应用于电子控制器上的一种通用语言.通过此协议,控制器相互之间.控制器经由网络/串口和其它设备之间可以进行通信.它已经成为了一种工业标准.有了这个通信协议,不同的厂商生成的控制设备就可 ...

  9. AQS源码深入分析之独占模式-ReentrantLock锁特性详解

    本文基于JDK-8u261源码分析 相信大部分人知道AQS是因为ReentrantLock,ReentrantLock的底层是使用AQS来实现的.还有一部分人知道共享锁(Semaphore/Count ...

  10. pycharm pro2020版专业版永久激活

    pycharm2020版本专业版永久激活[亲测有效] pycharm2020.1版安装包与破解工具下载 可私信我获取资源. 公众号,轻松学编程 教程 1.先下载安装包和破解补丁压缩包,然后点击pych ...