题目:有一个最多包含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. 从Linux源码看Socket(TCP)的bind

    从Linux源码看Socket(TCP)的bind 前言 笔者一直觉得如果能知道从应用到框架再到操作系统的每一处代码,是一件Exciting的事情. 今天笔者就来从Linux源码的角度看下Server ...

  2. Python爬虫框架--Scrapy安装以及简单实用

    scrapy框架 框架 ​ -具有很多功能且具有很强通用性的一个项目模板 环境安装: Linux: ​        pip3 install scrapy ​ ​ ​  Windows: ​     ...

  3. bootStrap小结3

    <!DOCTYPE html> <html lang="en"> <head> <meta http-equiv="Conten ...

  4. Linux系统快速搭建LAMP

    LAMP是 Linux + Apache + MySQL + PHP 的环境要求,即web服务器. 1.前置条件: (1)搭建Linux系统(参考博客:https://www.cnblogs.com/ ...

  5. docker启动服务---------------mysql

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

  6. linux(centos8):用systemctl管理war包形式的jenkins(java 14 / jenkins 2.257)

    一,如何安装jenkins? 参见: https://www.cnblogs.com/architectforest/p/13685904.html 说明:刘宏缔的架构森林是一个专注架构的博客,地址: ...

  7. Redis基础——剖析基础数据结构及其用法

    这是一个系列的文章,打算把Redis的基础数据结构.高级数据结构.持久化的方式以及高可用的方式都讲一遍,公众号会比其他的平台提前更新,感兴趣的可以提前关注,「SH的全栈笔记」,下面开始正文. 如果你是 ...

  8. vue渐进式开发的理解和指令

    1.vue渐进式开发 vue是一个渐进式的框架,轻量,易于上手,为啥是渐进式那,我当时也很蒙,比如的官网是jquery写的,就可以通过script标签引入事先准备好的vue.min.js的压缩源代码或 ...

  9. Vue中封装axios组件实例

    首先要创建一个网络模块network文件夹  里面要写封装好的几个组件 在config.js里面这样写 在index.js要这样写 core.js文件里面内容如下 然后要在main.js文件里面要设置 ...

  10. git学习(十一) idea git pull 解决冲突

    测试如下: 先将远程的代码修改,之后更新: 之后将工作区修改的代码(这里修改的代码跟远程修改的位置一样)提交到本地,之后拉取远程的代码,会发现有冲突: Accept Yours 就是直接选取本地的代码 ...