题目:有一个最多包含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. pytest文档44-allure.dynamic动态生成用例标题

    前言 pytest 结合 allure 描述用例的时候我们一般使用 @allure.title 和 @allure.description 描述测试用例的标题和详情. 在用例里面也可以动态更新标题和详 ...

  2. 闭嘴,给你一个数!1分钟,学完C语言指针,不扎手只扎心的针!

    序言 指针是C语言学习者绕不过的一道坎,也是C语言学习者不得绕过的一道坎.辨别一个人C语言学的好赖就看他对指针的理解怎么样.指针内容也是工作面试经常问到的问题.本文将带你重新认识那个绊倒你的指针,以解 ...

  3. spring boot:单文件上传/多文件上传/表单中多个文件域上传(spring boot 2.3.2)

    一,表单中有多个文件域时如何实现说明和文件的对应? 1,说明和文件对应 文件上传页面中,如果有多个文件域又有多个相对应的文件说明时, 文件和说明如何对应? 我们在表单中给对应的file变量和text变 ...

  4. CentOS8平台php日志的定时切分

    一,编写bash脚本: [root@yjweb crontab]# vi split_php_logs.sh 代码: #!/bin/bash # 备份php/php-fpm的日志 # 昨天的日期 fi ...

  5. spring-boot-route(十九)spring-boot-admin监控服务

    SpringBootAdmin不是Spring官方提供的模块,它包含了Client和Server两部分.server部分提供了用户管理界面,client即为被监控的服务.client需要注册到serv ...

  6. http请求需要了解的一些信息

    http请求需要了解的一些信息 http请求头:https://jingyan.baidu.com/article/375c8e19770f0e25f2a22900.htmlhttp状态码 :http ...

  7. C++学习笔记---引用的本质

    本质:引用本质上是C++内部实现的一个指针常量 发现是引用的话,自动帮我们转换成指针常量 运行后,发现修改ref的值那么a的值也会一起改变,这就说明了引用的本质就是指针

  8. Cloudera Manager简介

    Hadoop家族 整个Hadoop家族由以下几个子项目组成: Hadoop Common: Hadoop体系最底层的一个模块,为Hadoop各子项目提供各 种工具,如:配置文件和日志操作等. HDFS ...

  9. HelloGitHub 开源月刊(第 55 期):终端“百战天虫”,来战?

    兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...

  10. Sublime Text:性感无比的代码编辑器安装破解配置教程

    代码编辑器或者文本编辑器,对于程序员来说,就像剑与战士一样,谁都想拥有一把可以随心驾驭且锋利无比的宝剑,而每一位程序员,同样会去追求最适合自己的强大.灵活的编辑器,相信你和我一样,都不会例外. 我用过 ...