题目:有一个最多包含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. centos8上添加sudoer用户

    一,检查服务器是否已安装sudo的rpm包? 1,查询rpm包列表 [root@yjweb ~]# rpm -qa | grep sudo libsss_sudo-2.0.0-43.el8_0.3.x ...

  2. 笔趣阁小说 selenium爬取

    import re from time import sleep from lxml import etree from selenium import webdriver options = web ...

  3. centos 开机启动服务 systemctl

    systemctl 实现开机自启服务 转载起一个好听的名字 最后发布于2018-06-26 13:49:06 阅读数 13473  收藏 展开 systemctl是RHEL 7 的服务管理工具中主要的 ...

  4. 为什么堆化 heapify() 只用 O(n) 就做到了?

    heapify() 前面两篇文章介绍了什么是堆以及堆的两个基本操作,但其实呢,堆还有一个大名鼎鼎的非常重要的操作,就是 heapify() 了,它是一个很神奇的操作, 可以用 O(n) 的时间把一个乱 ...

  5. 跟我一起学Redis之看完这篇比常人多会三种类型实战(又搞了几个小时)

    前言 对于Redis而言,很多小伙伴只关注其关键的五大基础类型:string.hash.list.set.sorted set(有序集合),其实还有三种特殊类型在很多应用场景也比较适合使用,分别是:b ...

  6. Cypress系列(69)- route() 命令详解

    如果想从头学起Cypress,可以看下面的系列文章哦 https://www.cnblogs.com/poloyy/category/1768839.html 作用 管理控制整个网络请求 重要注意事项 ...

  7. Windows搭建Hexo系统

    date: 2018-11-16 17:10:51 updated: 2018-11-16 20:04:43 1.安装Git 下载Windows下的Git客户端并安装,安装很简单,基本一路Next下去 ...

  8. python接口自动化测试遇到的问题及解决方案

    工作中xml中的某一个字段是全网唯一,这就需要进行参数化处理.此次对这一个字段进行参数化处理引用了random模块和index()函数.代码如下: #!/usr/bin/python # -*- co ...

  9. Java基础知识(三)

    一.hashCode 与 equals (重要) 面试官可能会问你:"你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?" 1 ...

  10. JDK8中的新时间API:Duration Period和ChronoUnit介绍

    目录 简介 Duration Period ChronoUnit 简介 在JDK8中,引入了三个非常有用的时间相关的API:Duration,Period和ChronoUnit. 他们都是用来对时间进 ...