Abbott’s Revenge

PS:因为该题排版较麻烦,这里给出OJ网址:UVa816 - Abbott’s Revenge


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

这个迷宫的特殊之处在于:进入一个交叉点的方向(用NEWS这4个字母分别表示北东西南,即上右左下)不同,允许出去的方向也不同。例如,1 2 WLF NR ER 表示交叉点(1,2)(上数第1行,左数第2列)有3个路标(字符“”只是结束标志),如果进入该交叉点时的朝向为W(即朝左),则可以左转(L)或者直行(F);如果进入时朝向为N或者E则只能右转(R),如图6-14所示。注意:初始状态是“刚刚离开入口”,所以即使出口和入口重合,最短路也不为空。例如,图中的一条最短路为(3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1) (2,1) (2,2) (1,2) (1,3) (2,3) (3,3)。

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>using namespace std;// 节点类
// 站在(row,column)上,朝向dir方
// dir的取值范围为[0-3],分别表示N,E,S,W
struct Node {// 行int row;// 列int column;// 朝向int dir;// 构造方法Node(int row = 0, int column = 0, int dir = 0):row(row),column(column),dir(dir){ }
};const int maxNum = 10;
// 站在(i,j)面朝k方位,能否转向到m
// m取值范围为[0,2],0:向前,1:向左,2:向右
int has_edge[maxNum][maxNum][4][3];
// 初始点到(r,c,dir)的最短路径长度
int d[maxNum][maxNum][4];
// (r,c,dir)父节点的三元组
Node p[maxNum][maxNum][4];
// 初始点(r0,c0)及其朝向
int r0, c0, dir;
// 初始点向dir方向走了一步的位置(r1,c1)
int r1, c1;
// 出口位置(r2,c2)
int r2, c2;// 朝向,上右下左
const char* dirs = "NESW";
// 转向,前左右
const char* turns = "FLR";
// 通过字符c来判断朝向
// 0:N 1:E 2:S 3:W
// 原理为strchr函数是在dirs中找c字符
// 找到,则返回指向c字符位置的指针
// 然后减去dirs的指针,就能获取相应位置了
int dir_id(char c) {return strchr(dirs, c) - dirs;
}// 通过字符c来判断转向
// 0:F 1:L 2:R
// 原理和dir_id()一样
int turn_id(char c) {return strchr(turns, c) - turns;
}// 位移变化数组
// 0:组合起来向上了一步
// 1:组合起来向右了一步
// 2:组合起来向下了一步
// 3:组合起来向左了一步
const int dr[] = {-1, 0, 1,  0};
const int dc[] = { 0, 1, 0, -1};// 行走函数,通过该函数可以获得下一步的位置
Node walk(const Node &u, int turn) {int dir = u.dir;// 向左转if(turn == 1) {dir = (dir + 3) % 4;}// 向右转if(turn == 2) {dir = (dir + 1) % 4;}return Node(u.row + dr[dir], u.column + dc[dir], dir);
}// 读取一组用例
bool readCase() {// 用例名和初始朝向char s[99], s2[99];if(scanf("%s%d%d%s%d%d", s, &r0, &c0, s2, &r2, &c2) != 6) {return false;}printf("%s\n", s);// 初始化初始节点的下一个节点dir = dir_id(s2[0]);r1 = r0 + dr[dir];c1 = c0 + dc[dir];memset(has_edge, 0, sizeof(has_edge));while(true) {// 行列int r, c;scanf("%d", &r);if(r == 0) {break;}scanf("%d", &c);while(scanf("%s", s) == 1 && s[0] != '*') {// s[0]为当前朝向// s[1-n]为能够转向的方向for(int i = 1; i < strlen(s); i++) {has_edge[r][c][dir_id(s[0])][turn_id(s[i])] = 1;}}}return true;
}// 打印信息
void printAns(Node u) {// 从目标节点追溯到初始节点vector<Node> nodes;while(true) {nodes.push_back(u);// 初始节点的下一个节点退出if(d[u.row][u.column][u.dir] == 0) {break;}u = p[u.row][u.column][u.dir];}// 初始节点nodes.push_back(Node(r0, c0, dir));// 打印结果,每行10个// 每行最前面两个空格,(r,c)间一个空格int num = 0;for(int i = nodes.size() - 1; i >= 0; i--) {if(num % 10 == 0) {printf(" ");}printf(" (%d,%d)", nodes[i].row, nodes[i].column);if(++num % 10 == 0) {printf("\n");}}if(nodes.size() % 10 != 0) {printf("\n");}
}// 是否在范围内
bool inside(int r, int c) {return r >= 1 && r <= 9 && c >= 1 && c <= 9;
}// 采用BFS解决问题
void solve() {// 节点队列queue<Node> q;memset(d, -1, sizeof(d));Node u(r1, c1, dir);d[u.row][u.column][u.dir] = 0;q.push(u);while(!q.empty()) {Node u = q.front();q.pop();// 找到出口if(u.row == r2 && u.column == c2) {printAns(u);return;}// 0:F 1:L 2:Rfor(int i = 0; i < 3; i++) {// 转向方位都试探性的走一步Node v = walk(u, i);// 满足能够向该方向转// 移动之后还在边界内// 该点还没有被走过if(has_edge[u.row][u.column][u.dir][i] &&inside(v.row, v.column) && d[v.row][v.column][v.dir] < 0) {// 距离+1d[v.row][v.column][v.dir] = d[u.row][u.column][u.dir] + 1;// 设置父节点p[v.row][v.column][v.dir] = u;// 入队列q.push(v);}}}printf("  No Solution Possible\n");
}int main () {while(readCase()) {solve();}return 0;
}

816 - Abbott's Revenge相关推荐

  1. Abbott's Revenge UVA - 816 (输出bfs路径)

    题目链接:https://vjudge.net/problem/UVA-816 题目大意: 有一个最多包含9*9 个交叉点的迷宫.输入起点,离开起点时的朝向和终点,求一条最短路(多解时任意输出 一个即 ...

  2. UVA816 Abbott的复仇 Abbott's Revenge(final的BFS)(真•答案)

    题目 写这道题差点没把我气死,网上的好多题解看了半天结果是假的- 题目PDF [分析] 利用队列实现广度搜索BFS来遍历图寻找最短路径. 用一个三元组(r, c, dir)表示"位于(r, ...

  3. UVa816 例题 6-14 Abbott的复仇 (Abbott's Revenge,ACM/ICPC World Finals 2000)

    原题链接: UVa-816 题目大意: 模有一个最多包含9*9个交叉点的迷宫.输入起点.离开起点时的朝向和终点,求一条最短路径.(具体题目参考原题和紫书) 解题思路: 本题是一道用BFS求最短路径的迷 ...

  4. uva816 Abbott's Revenge (BFS+回溯)

    题目大意 给你个迷宫,求最短路,不过在每个点转弯的方向受进入方向的限制 思路 确定好每个点的状态,再用bfd求出最短路,注意记得用个数组保存节点,以方便输出 事实上很多细节都是参考刘汝佳老师的,感觉非 ...

  5. UVa 816 (BFS求最短路)

    /*816 - Abbott's Revenge ---代码完全参考刘汝佳算法入门经典 ---strchr() 用来查找某字符在字符串中首次出现的位置,其原型为:char * strchr (cons ...

  6. 紫书《算法竞赛入门经典》

    紫书<算法竞赛入门经典>题目一览 第3章 数组和字符串(例题) UVA 272 TEX Quotes UVA 10082 WERTYU UVA 401 Palindromes UVA 34 ...

  7. 《算法竞赛入门经典(第2版)》——学习记录

    前言:   这里主要记录本人在学习紫书过程中充分理解过的题目的AC代码,便于以后回顾时查找代码和思路,毕竟看别人的真的有点难懂.此外,本书甚至是本书之外的相关知识学习也可能在此留下记录.   作为一只 ...

  8. 【算法】BFS刷题总结

    姊妹篇(DFS) 目录 一.入门级 P1747 好奇怪的游戏 TRDD got lost again 二.进阶 final的BFS Abbott's Revenge 一.入门级 P1747 好奇怪的游 ...

  9. BFS,优先队列优化

    题意: 'S' : 起点 'T' : 终点 '#' : 毒气室 'B' :氧气 'P':不消耗步数 每次经过毒气室需要一瓶氧气,氧气可以重复获得,但只能带五瓶氧气,问最少步数 solution: HI ...

最新文章

  1. 【Python】Scrapy爬虫实战(豆瓣电影 Top 250)
  2. WCF入门教程(vs2010)
  3. linux清空串口接收buff,openwrt解除console对串口的占用
  4. centos iptables_SQLyog远程连接centos中mysql数据库
  5. yamlip 安装_prometheus.(1).yaml安装
  6. python面向对象的特征_03 Python 关键点讲解:面向对象的机制
  7. 十大算法 — 选择排序法【C语言代码诠释】
  8. 你不专业并且自以为是,所以被坑
  9. 746. Min Cost Climbing Stairs
  10. 电子工程师必须知道的12个知识
  11. cherry 键盘失灵记录
  12. ICCV2019 | 锁定视频中的目标:港大提出运动注意力检测方法
  13. 从薛定谔方程到K-S方程
  14. Kyrie Irving邀请粉丝加入Lineage Logistics的Share A Meal运动,帮助受COVID-19疫情影响的人们
  15. Falled to crcate the site. Peaseauthorize ArcGIS Server by navigating to the Apps page
  16. 【LeetCode】两道贪心算法题目-455分发饼干,860柠檬水找零
  17. java变位词_Java程序检查字符串是否是变位词
  18. arm linux 中littlevgl支持tslib的方法
  19. JAVA毕业设计web唐院寻人表白系统计算机源码+lw文档+系统+调试部署+数据库
  20. VLOOKUP命令不生效的坑

热门文章

  1. jmeter重写java请求_jmeter之编写java请求-扩展Java Sampler
  2. vue websocket 实时渲染页面
  3. 【Linux】Aria2 一键安装管理脚本 BT\PT一键安装包
  4. 【Python】第一个程序---Helloworld!
  5. 输入身份证号,输出出生日期
  6. Vercel反向代理做CDN,免费给网站加速隐藏源站,可绑定域名
  7. sqlalchemy通过已经存在的表生成model的方法
  8. 2016年最佳微小说系列
  9. word 职称计算机考试大纲,全国职称计算机考试Word2003大纲.doc
  10. 设计模式 代理模式和装饰模式的区别