关于
我的项目
相关阅读
热度排行
- [转] 宫崎骏用动漫教给我们的人生哲理,每一句都能说到心里! - (日期:[八月 24, 2013] 点击:[53,616])
- Google 网页爬虫报告无法连接站点解决办法 - (日期:[七月 20, 2014] 点击:[38,665])
- 架设Tiny Tiny RSS(TTRSS)阅读器,找回Google Reader! - (日期:[九月 27, 2013] 点击:[27,809])
- SkyDrive、DropBox和Google Drive三大公有云存储服务对比 - (日期:[六月 25, 2013] 点击:[25,674])
- 升级到至强E5440后,与i5 CPU笔记本性能对比 - (日期:[二月 18, 2014] 点击:[23,845])
- 公钥私钥加密解密数字证书数字签名详解 - (日期:[四月 19, 2014] 点击:[22,976])
- 本站建站技术合集 - (日期:[九月 20, 2013] 点击:[22,560])
- 使用OpenerDNS解决无法访问Google的问题 - (日期:[七月 5, 2014] 点击:[21,861])
- WordPress博客添加“返回顶部”按钮 - (日期:[七月 14, 2013] 点击:[21,286])
- Linux文件系统基础之inode和dentry - (日期:[三月 13, 2015] 点击:[20,224])
- 云存储中的HTTP鉴权算法分析 - (日期:[二月 7, 2014] 点击:[18,655])
- 存储基础知识之——磁盘阵列原理及操作实战 - (日期:[二月 9, 2014] 点击:[17,544])
- 精选37条强大的常用linux shell命令组合 - (日期:[九月 4, 2013] 点击:[17,470])
- DNS原理、架构和配置详解 - (日期:[九月 6, 2013] 点击:[16,877])
- Netty和Jetty的Java NIO 网络框架模型分析 - (日期:[七月 13, 2013] 点击:[16,352])
- CoreOS 初识之安装 - (日期:[十一月 16, 2014] 点击:[16,223])
- Windows与Linux文件系统互访的几种方法 - (日期:[八月 21, 2014] 点击:[15,739])
- Dijkstra算法求解最短路径分析 - (日期:[七月 12, 2014] 点击:[14,943])
- NAS解决方案实现多媒体文件共享播放 - (日期:[十二月 21, 2014] 点击:[13,968])
- 简介 - (日期:[九月 1, 2012] 点击:[13,794])
- 如何编程实现 2 + 2 = 5? - (日期:[六月 2, 2014] 点击:[13,278])
- 搭建了一个iNews程序 - (日期:[十月 15, 2013] 点击:[13,254])
- 2014年9月曝出的Bash ShellShock漏洞简析 - (日期:[九月 26, 2014] 点击:[13,171])
- 彻底解决WordPress博客垃圾评论的问题 - (日期:[八月 5, 2013] 点击:[13,168])
- 如何使用1M的内存排序100万个8位数 - (日期:[三月 27, 2014] 点击:[12,572])
- 全部日志列表 - (日期:[十一月 11, 2012] 点击:[12,435])
- 关于回调函数和this指针探讨 - (日期:[八月 24, 2014] 点击:[12,249])
- 开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南 - (日期:[四月 23, 2022] 点击:[11,894])
- 给定一个long型常量,其值为x,给定long型变量a,要求a & x 的取值集合 - (日期:[九月 8, 2012] 点击:[11,742])
- WordPress建站必备实用插件 - (日期:[八月 7, 2014] 点击:[11,389])
-
近期文章
- Golang PGO技术介绍 四月 13, 2025
- 3FS Usrbio 简介 四月 6, 2025
- NVIDIA 为 CUDA 添加原生 Python 支持:开启 GPU 计算新篇章 四月 5, 2025
- pico.sh服务简介 四月 4, 2025
- cloudflare的妙用 一月 11, 2025
- 介绍一个生产力工具:ntfy 十二月 24, 2024
- 困扰了快1个月的家用宽带网络卡顿问题-Linux病毒实战手记 四月 21, 2024
- HomeServer 2024升级计划 二月 11, 2024
- HomeServer直播、监控方案实践 九月 28, 2023
- 我的2022 一月 7, 2023
近期评论
- 匿名发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- 1发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- xxgl发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- 童燕群发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- xxgl发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- 童燕群发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- xxgl发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- 童燕群发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- xxgl发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
- xxgl发表在《开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南》
分类目录
文章归档
- 2025年四月 (4)
- 2025年一月 (1)
- 2024年十二月 (1)
- 2024年四月 (1)
- 2024年二月 (1)
- 2023年九月 (1)
- 2023年一月 (1)
- 2022年十月 (1)
- 2022年八月 (2)
- 2022年四月 (1)
- 2022年三月 (1)
- 2021年十二月 (2)
- 2021年十月 (2)
- 2021年九月 (1)
- 2021年八月 (1)
- 2021年五月 (1)
- 2021年三月 (2)
- 2021年一月 (2)
- 2020年十二月 (5)
- 2020年十一月 (2)
- 2020年十月 (2)
- 2020年九月 (1)
- 2020年八月 (5)
- 2020年七月 (2)
- 2019年九月 (1)
- 2018年八月 (1)
- 2018年七月 (1)
- 2018年六月 (1)
- 2018年五月 (1)
- 2018年三月 (1)
- 2018年二月 (1)
- 2018年一月 (2)
- 2017年十二月 (3)
- 2017年十月 (4)
- 2017年九月 (1)
- 2017年七月 (1)
- 2017年六月 (1)
- 2016年十二月 (1)
- 2016年十月 (1)
- 2016年九月 (1)
- 2016年七月 (2)
- 2016年六月 (1)
- 2016年二月 (3)
- 2015年十二月 (3)
- 2015年十一月 (2)
- 2015年十月 (1)
- 2015年八月 (2)
- 2015年七月 (4)
- 2015年六月 (1)
- 2015年三月 (2)
- 2015年二月 (1)
- 2015年一月 (4)
- 2014年十二月 (2)
- 2014年十一月 (2)
- 2014年十月 (5)
- 2014年九月 (8)
- 2014年八月 (11)
- 2014年七月 (17)
- 2014年六月 (7)
- 2014年五月 (15)
- 2014年四月 (16)
- 2014年三月 (14)
- 2014年二月 (5)
- 2013年十二月 (5)
- 2013年十一月 (3)
- 2013年十月 (13)
- 2013年九月 (13)
- 2013年八月 (13)
- 2013年七月 (9)
- 2013年六月 (8)
- 2013年五月 (1)
- 2013年三月 (3)
- 2013年一月 (1)
- 2012年十一月 (1)
- 2012年九月 (12)
- 2012年八月 (3)
- 2011年二月 (1)
- 2009年三月 (1)
- 2009年二月 (1)
- 2008年十一月 (1)
- 2008年六月 (1)
- 2008年四月 (1)
- 2008年三月 (1)
广度优先搜索解决“营救公主”问题
在之前的一篇文章(迷宫营救公主算法)中提供了一个半成品的解决方案,之所以说他是半成品,是因为首先选择的算法就不对,采用的是深度优先搜索,其次也没有真正的用对深度优先算法,走过的点应该标记为已经走过,而不应该重复遍历该节点。下面的文章对于广度优先和深度优先两种算法的解释非常到位。今天准备把这个问题再完整的用正确的算法解答一遍。
文章链接:【图论】广度优先搜索和深度优先搜索。
就营救公主的问题而言,这里不再重复描述问题了,请点击这里查看题目分析:链接。这次选用广度优先算法来解决该问题。上面的算法介绍文章中对该算法已经分析得非常清晰了。先给解决本问题的算法伪代码:
这里每个节点有三种状态:
*)该状态表示墙,如果访问到该类型节点,则不用继续遍历。应退回至上层节点。
.)该状态表示该节点通行,访问到该节点应该将节点压入队列。并将该节点标记为已经访问。为区别图中已经有的几种元素,这里定义一个新的标记’#’来表示已经访问过的节点。同时可以使用一个二维数组记录从起始节点到该节点的访问距离step[i][j],该值应该是由其上一个节点的值加1之后得到。这样起始节点的值为1,依次每一个节点的距离都可以得到。
P)该状态表示已经搜索到了公主的位置,搜索结束。这时给出P点的距离,如果该距离值在给定的范围内,则可以营救出公主,否则失败。
解决问题的关键在于用一个step数组记录每个节点的距离起始点的距离,另外用一个’#’字符标记该节点已经被访问过,避免走“回头路”。
BFS(G, s) init V[G] // 由测试用例实现。 status[s] = S // s王子的位置,通过一次遍历可以获取其坐标。 int count = -1; queue q q.add(s) // 将王子的位置入队。 while !q.isEmpty() t = q.poll() for each vertex v in Adj[t] // 与t邻接的点 if status[v] = 'P' // 只对未访问的操作 count = step[v] = step[t] + 1 q.clear() break elseif status[v] = '.' status[v] = '#' // 标记为已经走过该节点 q.add(v) step[v] = step[t] + 1 // 累加得到当前节点的步长 elseif status[v] = '*' step[v] = -1 // 遇到墙,则将该节点的距离置为-1,在遍历完整个图时, // 如果遇到最后一个节点的值为-1,则表明没有找到。 else error if count != -1 if count < L return true return false
有了上面的伪代码,翻译成代码也就非常简单了。
import java.util.LinkedList; import java.util.List; import java.util.Queue; /** * 公主被魔王抓走了,王子需要拯救出美丽的公主。他进入了魔王的城堡,魔王的城堡是一座很大的迷宫。 * 为了使问题简单化,我们假设这个迷宫是一个N*M的二维方格。迷宫里有一些墙,王子不能通过。王子只 * 能移动到相邻(上下左右四个方向)的方格内,并且一秒只能移动一步。地图由'S','P','.','*' * 四种符号构成,'.'表示王子可以通过,'*'表示墙,王子不能通过;'S'表示王子的位置;'P'表示公主 * 的位置;T表示公主存活的剩余时间,王子必须在T秒内到达公主的位置,才能救活公主。如下图所示: */ public class SavePrincess { private int m; private int n; private char[][] visited; private Position s = null; private Position p = null; public static void main(String[] args) { char maze[][] = { /* 0 1 2 3 4 5 6 7 8 9 */ /* 0 */{ '.', '*', '.', '.', '.', '*', '.', '.', '.', '.' }, /* 1 */{ '*', 'S', '*', '.', '.', '.', '.', '.', '.', '.' }, /* 2 */{ '.', '*', '*', '.', '.', '.', '.', '.', '.', '.' }, /* 3 */{ '.', '.', '*', '*', '*', '.', '.', '.', '.', '.' }, /* 4 */{ '.', '.', '.', '.', '.', '.', '.', '.', '.', '.' }, /* 5 */{ '.', '.', '.', '.', '*', '.', '.', '.', '.', '.' }, /* 6 */{ '.', '.', '.', '.', '*', '.', '.', '.', '.', '.' }, /* 7 */{ '.', '.', '.', '.', '*', '.', '.', '.', '.', '.' }, /* 8 */{ '.', '.', '.', '.', '*', '.', '.', '.', '.', '.' }, /* 9 */{ '.', 'P', '.', '.', '*', '.', '.', '.', '.', '.' } }; new SavePrincess().saved(maze, 10, 8, 11); } /** * @param vis * M行N列迷宫 * @param m * M * @param n * N * @param t * T * * @return boolean true表示营救成功,反之表示失败。 */ public boolean saved(char[][] vis, int m, int n, int t) { if (t < 0) { return false; } this.m = m; this.n = n; this.visited = vis; int step[][] = new int[m][n]; init(m, n, step); if (s == null || p == null) { System.out.println("input visited error!"); return false; } Queue<Position> queue = new LinkedList<Position>(); queue.add(s); int l = -1; while (!queue.isEmpty()) { Position e = queue.poll(); l = dealOneNode(step, queue, e); } if (l != -1 && l <= t) { System.out.println("Saved the princess in " + l + " seconds!"); return true; } System.out.println("failed saved the princess! " + l + " > " + "t"); return false; } private void init(int m, int n, int[][] step) { for (int i = 0; i != m; i++) { for (int j = 0; j != n; j++) { System.out.print(visited[i][j]); System.out.print(' '); step[i][j] = 0; switch (visited[i][j]) { case '*': break; case 'S': this.s = new Position(i, j, 'S'); break; case '.': break; case 'P': this.p = new Position(i, j, 'P'); break; default: System.out.println("input visited error!"); System.exit(-1); } } System.out.println(""); } } private int dealOneNode(int[][] step, Queue<Position> queue, Position e) { /** * 在求相邻节点时做了一点优化,遇到墙的节点则不放到相邻节点中。 * 从设计思想和可读性上看不是太好,从运行效率考虑,可以。 */ for (Position c : getNextPostions(e)) { switch (c.getV()) { case 'P': queue.clear(); return step[e.getI()][e.getJ()] + 1; case '.': visited[c.getI()][c.getJ()] = '#'; queue.add(c); step[c.getI()][c.getJ()] = step[e.getI()][e.getJ()] + 1; break; default: // 不可能进入该分支。 System.err.println("some error!"); break; } } return -1; } /** * 取有效节点。 * 遇到墙则不加入相邻节点中。 * * @param e * @return */ private List<Position> getNextPostions(Position e) { int i = e.getI(); int j = e.getJ(); List<Position> lst1 = new LinkedList<Position>(); addOneNode(i + 1, j, lst1); addOneNode(i, j + 1, lst1); addOneNode(i - 1, j, lst1); addOneNode(i, j - 1, lst1); return lst1; } private void addOneNode(int i, int j, List<Position> lst) { if (i >= m || i < 0 || j >= n || j < 0) { return; } char v = visited[i][j]; switch (v) { case '.': case 'P': lst.add(new Position(i, j, v)); break; default: break; } } private class Position { private int i; private int j; private char v; public Position(int i, int j, char value) { this.i = i; this.j = j; this.v = value; } public char getV() { return v; } public int getI() { return i; } public int getJ() { return j; } public String toString() { return "(" + i + ", " + j + ")"; } } }
6 条评论
char maze[][] = {
/* 0 1 2 3 4 5 6 7 8 9 */
/* 0 */{'.', '.', '.', '.', '.', '*', '.', '.', '.', '.'},
/* 1 */{'.', 'P', '.', '.', '.', '.', '.', '.', '.', '.'},
/* 2 */{'.', '*', '.', '.', '.', '.', '.', '.', '.', '.'},
/* 3 */{'.', '.', '*', '*', '*', '.', '.', '.', '.', '.'},
/* 4 */{'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'},
/* 5 */{'.', '.', '.', '.', '*', '.', '.', '.', '.', '.'},
/* 6 */{'.', '.', '.', '.', '*', '.', '.', '.', '.', '.'},
/* 7 */{'.', '.', '.', '.', '*', '.', '.', '.', '.', '.'},
/* 8 */{'.', '.', '.', '.', '*', '.', '.', '.', '.', '.'},
/* 9 */{'.', 'S', '.', '.', '*', '.', '.', '.', '.', '.'}};
这个矩阵得出的结果不对,不是最优解
然后解的路径没有。只有是否能在规定步数内救出公主的true?false,需要输出最优解的路径
根据这个迷宫,已经找到了代码中的bug,并修改了日志中代码。
这位同学测试得好细心啊。赞并感谢!!
你提出的记录路劲的需求,应该是要扩充每遍历一个节点时,不仅仅要记录该节点距离起始点“S”的距离,还需要记录起始节点“S”到当前节点的轨迹,这样就可以在找到公主时打印出路径了。因此setup不是一个简单的int型的二维数组,而应该是一个符合类型对象的二维数组,该对象中包含了距离和所经过的节点的链表。
增加路径记录的代码如下:
运行结果:
. * . . . * . .
. S . . . . . .
* * * . . . . .
. . * . * . . .
. . . . . . . .
. . . . * . . .
. . . . * . . .
. . . . * . . .
. . . . * . . .
. P . . * . . .
Saved the princess in (step: 11, path: [1, 2] -> [1, 3] -> [2, 3] -> [3, 3] -> [4, 3] -> [5, 3] -> [6, 3] -> [7, 3] -> [8, 3] -> [9, 3] -> [9, 2] -> [9, 1]) seconds!
对于网站降权方面,我能博主一些问题么。我的一个网站www.caizicheng.com六月份改版之后,被降权了。不过在7月份有一段时间,权重回来之后现在又被降权了。而且,这次网站的首页也找不到了。
现在,我应该从那些方面着手来恢复网站的权重。
在这方面,你比我懂得多多了。我只觉得一个稳固而实用的界面和充实的内容非常重要。