关于
我的项目
相关阅读
热度排行
- [转] 宫崎骏用动漫教给我们的人生哲理,每一句都能说到心里! - (日期:[八月 24, 2013] 点击:[53,606])
- Google 网页爬虫报告无法连接站点解决办法 - (日期:[七月 20, 2014] 点击:[38,665])
- 架设Tiny Tiny RSS(TTRSS)阅读器,找回Google Reader! - (日期:[九月 27, 2013] 点击:[27,806])
- SkyDrive、DropBox和Google Drive三大公有云存储服务对比 - (日期:[六月 25, 2013] 点击:[25,670])
- 升级到至强E5440后,与i5 CPU笔记本性能对比 - (日期:[二月 18, 2014] 点击:[23,841])
- 公钥私钥加密解密数字证书数字签名详解 - (日期:[四月 19, 2014] 点击:[22,976])
- 本站建站技术合集 - (日期:[九月 20, 2013] 点击:[22,556])
- 使用OpenerDNS解决无法访问Google的问题 - (日期:[七月 5, 2014] 点击:[21,857])
- WordPress博客添加“返回顶部”按钮 - (日期:[七月 14, 2013] 点击:[21,276])
- Linux文件系统基础之inode和dentry - (日期:[三月 13, 2015] 点击:[20,220])
- 云存储中的HTTP鉴权算法分析 - (日期:[二月 7, 2014] 点击:[18,655])
- 存储基础知识之——磁盘阵列原理及操作实战 - (日期:[二月 9, 2014] 点击:[17,543])
- 精选37条强大的常用linux shell命令组合 - (日期:[九月 4, 2013] 点击:[17,469])
- DNS原理、架构和配置详解 - (日期:[九月 6, 2013] 点击:[16,875])
- Netty和Jetty的Java NIO 网络框架模型分析 - (日期:[七月 13, 2013] 点击:[16,350])
- CoreOS 初识之安装 - (日期:[十一月 16, 2014] 点击:[16,220])
- Windows与Linux文件系统互访的几种方法 - (日期:[八月 21, 2014] 点击:[15,739])
- Dijkstra算法求解最短路径分析 - (日期:[七月 12, 2014] 点击:[14,942])
- NAS解决方案实现多媒体文件共享播放 - (日期:[十二月 21, 2014] 点击:[13,967])
- 简介 - (日期:[九月 1, 2012] 点击:[13,790])
- 如何编程实现 2 + 2 = 5? - (日期:[六月 2, 2014] 点击:[13,278])
- 搭建了一个iNews程序 - (日期:[十月 15, 2013] 点击:[13,252])
- 2014年9月曝出的Bash ShellShock漏洞简析 - (日期:[九月 26, 2014] 点击:[13,170])
- 彻底解决WordPress博客垃圾评论的问题 - (日期:[八月 5, 2013] 点击:[13,163])
- 如何使用1M的内存排序100万个8位数 - (日期:[三月 27, 2014] 点击:[12,570])
- 全部日志列表 - (日期:[十一月 11, 2012] 点击:[12,426])
- 关于回调函数和this指针探讨 - (日期:[八月 24, 2014] 点击:[12,246])
- 开源好用的电子书管理服务Talebook(Calibre网络版)安装使用指南 - (日期:[四月 23, 2022] 点击:[11,852])
- 给定一个long型常量,其值为x,给定long型变量a,要求a & x 的取值集合 - (日期:[九月 8, 2012] 点击:[11,741])
- WordPress建站必备实用插件 - (日期:[八月 7, 2014] 点击:[11,388])
分类目录
文章归档
- 2025年四月 (3)
- 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型的二维数组,而应该是一个符合类型对象的二维数组,该对象中包含了距离和所经过的节点的链表。
01
char
maze[][] = {
02
/* 0 1 2 3 4 5 6 7 8 9 */
03
/* 0 */{'.', '.', '.', '.', '.', '*', '.', '.', '.', '.'},
04
/* 1 */{'.', 'P', '.', '.', '.', '.', '.', '.', '.', '.'},
05
/* 2 */{'.', '*', '.', '.', '.', '.', '.', '.', '.', '.'},
06
/* 3 */{'.', '.', '*', '*', '*', '.', '.', '.', '.', '.'},
07
/* 4 */{'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'},
08
/* 5 */{'.', '.', '.', '.', '*', '.', '.', '.', '.', '.'},
09
/* 6 */{'.', '.', '.', '.', '*', '.', '.', '.', '.', '.'},
10
/* 7 */{'.', '.', '.', '.', '*', '.', '.', '.', '.', '.'},
11
/* 8 */{'.', '.', '.', '.', '*', '.', '.', '.', '.', '.'},
12
/* 9 */
{
'.'
,
'S'
,
'.'
,
'.'
,
'*'
,
'.'
,
'.'
,
'.'
,
'.'
,
'.'
}};
增加路径记录的代码如下:
001
import
java.util.LinkedList;
002
import
java.util.List;
003
import
java.util.Queue;
004
005
/**
006
* 公主被魔王抓走了,王子需要拯救出美丽的公主。他进入了魔王的城堡,魔王的城堡是一座很大的迷宫。
007
* 为了使问题简单化,我们假设这个迷宫是一个N*M的二维方格。迷宫里有一些墙,王子不能通过。王子只
008
* 能移动到相邻(上下左右四个方向)的方格内,并且一秒只能移动一步。地图由'S','P','.','*'
009
* 四种符号构成,'.'表示王子可以通过,'*'表示墙,王子不能通过;'S'表示王子的位置;'P'表示公主
010
* 的位置;T表示公主存活的剩余时间,王子必须在T秒内到达公主的位置,才能救活公主。如下图所示:
011
*/
012
public
class
SavePrincess
013
{
014
private
int
m;
015
private
int
n;
016
private
char
[][] visited;
017
private
Position s =
null
;
018
private
Position p =
null
;
019
020
public
static
void
main(String[] args)
021
{
022
char
maze[][] = {
023
/* 0 1 2 3 4 5 6 7 8 9 */
024
/* 0 */{ '.', '*', '.', '.', '.', '*', '.', '.', '.', '.' },
025
/* 1 */{ '.', 'S', '.', '.', '.', '.', '.', '.', '.', '.' },
026
/* 2 */{ '*', '*', '*', '.', '.', '.', '.', '.', '.', '.' },
027
/* 3 */{ '.', '.', '*', '.', '*', '.', '.', '.', '.', '.' },
028
/* 4 */{ '.', '.', '.', '.', '.', '.', '.', '.', '.', '.' },
029
/* 5 */{ '.', '.', '.', '.', '*', '.', '.', '.', '.', '.' },
030
/* 6 */{ '.', '.', '.', '.', '*', '.', '.', '.', '.', '.' },
031
/* 7 */{ '.', '.', '.', '.', '*', '.', '.', '.', '.', '.' },
032
/* 8 */{ '.', '.', '.', '.', '*', '.', '.', '.', '.', '.' },
033
/* 9 */{ '.', 'P', '.', '.', '*', '.', '.', '.', '.', '.' } };
034
035
new SavePrincess().saved(maze, 10, 8, 20);
036
}
037
038
/**
039
* @param vis
040
* M行N列迷宫
041
* @param m
042
* M
043
* @param n
044
* N
045
* @param t
046
* T
047
*
048
* @return boolean true表示营救成功,反之表示失败。
049
*/
050
public boolean saved(char[][] vis, int m, int n, int t)
051
{
052
if (t < 0)
053
{
054
return false;
055
}
056
057
this.m = m;
058
this.n = n;
059
this.visited = vis;
060
Step step[][] = new Step[m][n];
061
062
init(m, n, step);
063
064
if (s == null || p == null)
065
{
066
System.out.println("input visited error!");
067
return false;
068
}
069
070
Queue<Position> queue = new LinkedList<Position>();
071
queue.add(s);
072
Step l = null;
073
while (!queue.isEmpty())
074
{
075
Position e = queue.poll();
076
l = dealOneNode(step, queue, e);
077
}
078
079
if (l != null && l.getStep() + 1 <= t)
080
{
081
System.out.println("Saved the princess in " + l + " seconds!");
082
return true;
083
}
084
085
System.out.println("failed saved the princess! " + l + " > " + "t");
086
return false;
087
}
088
089
private void init(int m, int n, Step[][] step)
090
{
091
for (int i = 0; i != m; i++)
092
{
093
for (int j = 0; j != n; j++)
094
{
095
System.out.print(visited[i][j]);
096
System.out.print(' ');
097
step[i][j] = new Step(0);
098
switch (visited[i][j])
099
{
100
case '*':
101
break;
102
case 'S':
103
this.s = new Position(i, j, 'S');
104
break;
105
case '.':
106
break;
107
case 'P':
108
this.p = new Position(i, j, 'P');
109
break;
110
default:
111
System.out.println("input visited error!");
112
System.exit(-1);
113
}
114
}
115
System.out.println("");
116
}
117
}
118
119
private Step dealOneNode(Step[][] step, Queue<Position> queue, Position e)
120
{
121
/**
122
* 在求相邻节点时做了一点优化,遇到墙的节点则不放到相邻节点中。
123
* 从设计思想和可读性上看不是太好,从运行效率考虑,可以。
124
*/
125
for (Position c : getNextPostions(e))
126
{
127
switch (c.getV())
128
{
129
case 'P':
130
queue.clear();
131
return step[e.getI()][e.getJ()];
132
case '.':
133
visited[c.getI()][c.getJ()] = '#';
134
queue.add(c);
135
step[c.getI()][c.getJ()].setStep(step[e.getI()][e.getJ()].step + 1);
136
List<Position> l = step[c.getI()][c.getJ()].getPath();
137
l.addAll(step[e.getI()][e.getJ()].path);
138
l.add(c);
139
break;
140
default:
141
// 不可能进入该分支。
142
System.err.println("some error!");
143
break;
144
}
145
}
146
return null;
147
}
148
149
/**
150
* 取有效节点。
151
* 遇到墙则不加入相邻节点中。
152
*
153
* @param e
154
* @return
155
*/
156
private
List<Position> getNextPostions(Position e)
157
{
158
int
i = e.getI();
159
int
j = e.getJ();
160
List<Position> lst1 =
new
LinkedList<Position>();
161
addOneNode(i +
1
, j, lst1);
162
addOneNode(i, j +
1
, lst1);
163
addOneNode(i -
1
, j, lst1);
164
addOneNode(i, j -
1
, lst1);
165
return
lst1;
166
}
167
168
private
void
addOneNode(
int
i,
int
j, List<Position> lst)
169
{
170
if
(i >= m || i <
0
|| j >= n || j <
0
)
171
{
172
return
;
173
}
174
175
char
v = visited[i][j];
176
switch
(v)
177
{
178
case
'.'
:
179
case
'P'
:
180
lst.add(
new
Position(i, j, v));
181
break
;
182
default
:
183
break
;
184
}
185
}
186
187
private
class
Position
188
{
189
private
int
i;
190
private
int
j;
191
private
char
v;
192
193
public
Position(
int
i,
int
j,
char
value)
194
{
195
this
.i = i;
196
this
.j = j;
197
this
.v = value;
198
}
199
200
public
char
getV()
201
{
202
return
v;
203
}
204
205
public
int
getI()
206
{
207
return
i;
208
}
209
210
public
int
getJ()
211
{
212
return
j;
213
}
214
215
public
String toString()
216
{
217
return
"["
+ i +
", "
+ j +
"]"
;
218
}
219
}
220
221
private
class
Step
222
{
223
private
int
step;
224
225
private
List<Position> path =
new
LinkedList<Position>();
226
227
public
Step(
int
step)
228
{
229
this
.step = step;
230
}
231
232
public
int
getStep()
233
{
234
return
step;
235
}
236
237
public
void
setStep(
int
step)
238
{
239
this
.step = step;
240
}
241
242
public
List<Position> getPath()
243
{
244
return
path;
245
}
246
247
@Override
248
public
String toString()
249
{
250
StringBuilder sb =
new
StringBuilder();
251
sb.append(
"("
).append(
"step: "
).append(step).append(
", path: "
);
252
if
(path !=
null
)
253
{
254
for
(Position pnode : path)
255
{
256
sb.append(pnode).append(
" -> "
);
257
}
258
}
259
sb.append(p).append(
")"
);
260
return
sb.toString();
261
}
262
}
263
264
}
运行结果:
. * . . . * . .
. 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月份有一段时间,权重回来之后现在又被降权了。而且,这次网站的首页也找不到了。
现在,我应该从那些方面着手来恢复网站的权重。
在这方面,你比我懂得多多了。我只觉得一个稳固而实用的界面和充实的内容非常重要。