本文转自:https://blog.csdn.net/seagal890/article/details/79826353
写的非常好的回溯法:
https://blog.csdn.net/versencoder/article/details/52071930
另外还有一个BFS和DFS的博文链接:https://blog.csdn.net/Gene1994/article/details/85097507
DFS算法题解两个例子(走迷宫和求排列组合数)
用DFS算法来求解几道题目。典型的问题是走迷宫问题。
####走迷宫题目描述
给定一个M*N的矩阵(二维数组),分别用0和1表示通路和障碍物。即 0 表示 通路;1 表示 障碍物。从矩阵的左上角开始,每次只能向右,下,左,上移动位置,不能斜着走。请给出从入口到出口的路线。
怎么开始思考呢?
首先想想,这个题目其实是找从入口(Entrance)到出口(Exit)的可能的路径。矩阵(二维数组)从左上角开始,坐标为(0,0),可以向右走,坐标为(0,1);或者向下走,坐标为(1,0)。对于一般的位置(x,y),可以有4个搜索方向:右(x,y+1),下(x+1,y),左(x,y-1),上(x-1,y)。
如何设计DFS搜索函数呢?
二维数组(M行,N列)的右下角出口位置可以表示为:(m-1, n-1)
路径表示为path ; 但是路径可能有很多条,其中最短的路径表示为:shortestPath。
至少这个函数需要三个参数。dfs(x坐标,y坐标,搜索矩阵即二维数组)
所定义dfs函数为:
public static void dfsMaze(int x,int y, int[][] maze)
- 1
然后设计搜索结束返回的判断条件
//设置结束条件
if (x < 0 || y < 0)
return;
// 如果坐标越界,或者 maze[x][y]==1 表示遇到障碍
if (x > m - 1 || y > n - 1 || maze[x][y] ==1)
return;
//表示遇到障碍
if (maze[x][y] == 1)
return; // 判断是否通路和越界
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
判断是否达到出口位置
if (x == m - 1 && y == n - 1) { // 判断是否抵达出口
path = path + "(" + x + "," + y + ")";
if (shortestPath.length() == 0 || shortestPath.length() > shortestPath.length())
shortestPath = path;
System.out.println("找到路线:" + path);
return;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
对于任意位置(二维数组的某一个位置)因为0代表通路,1代表障碍物,如果走过了可以到达的位置,将其设定一个标记为1
maze[x][y] = 1; // 将走过的路标记。当改路线搜索完成时,再清除此标记为0。
- 1
搜索方向可以表示为:
// 向四个方向搜索
dfsMaze(x + 1, y, maze); //向右搜索
dfsMaze(x, y + 1, maze); //向下搜索
dfsMaze(x, y - 1, maze); //向上搜索
dfsMaze(x - 1, y, maze); //向左搜索
- 1
- 2
- 3
- 4
- 5
它表示从上一个位置开始,向下一个位置搜索的坐标。
完整的代码如下所示:
package com.bean.algorithmbasic;
public class DFSMaze {
/**
* DFS算法解决走迷宫问题
* 0: 表示通路
* 1: 表示死路
*
*/
static String path = "";
static String shortestPath = "";
public static void dfsMaze(int x, int y, int[][] maze) {
/*
* 获得矩阵的大小
* */
int m=maze.length;
int n=maze[0].length;
//设置结束条件
if (x < 0 || y < 0)
return;
// 如果坐标越界,或者 maze[x][y]==1 表示遇到障碍
if (x > m - 1 || y > n - 1 || maze[x][y] ==1)
return;
//表示遇到障碍
if (maze[x][y] == 1)
return; // 判断是否通路和越界
if (x == m - 1 && y == n - 1) { // 判断是否抵达出口
path = path + "(" + x + "," + y + ")";
if (shortestPath.length() == 0 || shortestPath.length() > shortestPath.length())
shortestPath = path;
System.out.println("找到路线:" + path);
return;
}
String temp = path;
path = path + "(" + x + "," + y + ")" + "-"; // 记录路线
maze[x][y] = 1; // 将走过的路标记
// 向四个方向搜索
dfsMaze(x + 1, y, maze); //向右搜索
dfsMaze(x, y + 1, maze); //向下搜索
dfsMaze(x, y - 1, maze); //向上搜索
dfsMaze(x - 1, y, maze); //向左搜索
// 将路线和标记恢复成上一次的状态
maze[x][y] = 0;
//清除
path = temp;
}
public static void main(String[] args) {
// 初始化一个迷宫地图
// 0: 表示通路
// 1:表示死路
int[][] maze = {
{0, 0, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 0, 1, 1, 0, 1},
{1, 0, 1, 0, 0, 1, 0, 0, 1},
{1, 0, 1, 0, 1, 0, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 1},
{1, 1, 0, 1, 1, 0, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 0}
};
int[][] maze2 = {
{0, 0, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 0, 1, 1, 0, 1},
{1, 0, 1, 0, 0, 1, 0, 0, 1},
{1, 0, 1, 0, 1, 0, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 1},
{1, 1, 0, 1, 1, 0, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 1, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 0}
};
/*
* 从矩阵的左上角位置开始搜索
* */
dfsMaze(0, 0, maze);
if (shortestPath.length() != 0)
System.out.println("最短路线为:" + shortestPath);
else
System.out.println("没有找到路线!");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
运行结果为:
找到路线:(0,0)-(0,1)-(1,1)-(2,1)-(3,1)-(4,1)-(5,1)-(5,2)-(6,2)-(7,2)-(7,3)-(7,4)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
找到路线:(0,0)-(0,1)-(1,1)-(2,1)-(3,1)-(4,1)-(5,1)-(5,2)-(5,3)-(5,4)-(5,5)-(6,5)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
找到路线:(0,0)-(0,1)-(1,1)-(1,2)-(1,3)-(1,4)-(2,4)-(3,4)-(3,3)-(4,3)-(5,3)-(5,4)-(5,5)-(6,5)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
找到路线:(0,0)-(0,1)-(1,1)-(1,2)-(1,3)-(1,4)-(2,4)-(3,4)-(3,3)-(4,3)-(5,3)-(5,2)-(6,2)-(7,2)-(7,3)-(7,4)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
最短路线为:(0,0)-(0,1)-(1,1)-(2,1)-(3,1)-(4,1)-(5,1)-(5,2)-(6,2)-(7,2)-(7,3)-(7,4)-(7,5)-(7,6)-(7,7)-(7,8)-(8,8)
这里有一个问题,如果最短的路线不只一条,怎么处理?这个算法中并没有考虑这个问题。
所以这个算法还是有一定的瑕疵的。
####求排列组合数
假设给定3个数:1,2,3,求出其所有的排列组合情况。
例如:
1,1,1
1,1,2
1,1,3
1,2,1
1,2,2
1,2,3
……
3,3,3
这个问题也可以使用DFS算法求解。
那么该如何开始思考这个问题呢?
首先定义一个数组:
int[] array = new int[3];
- 1
数组元素表示为:array[0]=1; array[1]=2;array[2]=3
这个数组代表搜索的开始。从array[0]开始,第一种情况组合就是:1,1,1
设计DFS搜索函数的原型为:
public void dfsExample(int index)
- 1
其中:参数的含义是从目标数组中依次取出第几个元素。index代表数组元素的下标。
边界条件为:
// 边界条件 if (index == 3) {
for (int i = 0; i < 3; i++) { System.out.print(array[i]+" "); } System.out.println(); //走不下去了就 return了 return; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
搜索过程为:
for (int i = 1; i <= 3; i++)
{
array[index] = i;
// index+1 枚举下一种情况
dfsExample(index+1);
}
- 1
- 2
- 3
- 4
- 5
- 6
完整的算法设计如下:
package com.bean.algorithmbasic;
public class DFSDemo {
int[] num = new int[3];
public void dfsExample(int index)
{
// 边界条件
if (index == 3)
{
for (int i = 0; i < 3; i++)
{
System.out.print(num[i]+" ");
}
System.out.println();
//走不下去了就 return了
return;
}
for (int i = 1; i <= 3; i++)
{
num[index] = i;
// index+1 枚举下一种情况
dfsExample(index+1);
}
}
public static void main(String[] args) {
DFSDemo dfsdemo=new DFSDemo();
dfsdemo.dfsExample(0);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
输出结果如下所示:
1 1 1
1 1 2
1 1 3
1 2 1
1 2 2
1 2 3
1 3 1
1 3 2
1 3 3
2 1 1
2 1 2
2 1 3
2 2 1
2 2 2
2 2 3
2 3 1
2 3 2
2 3 3
3 1 1
3 1 2
3 1 3
3 2 1
3 2 2
3 2 3
3 3 1
3 3 2
3 3 3
这两个题目的求解结果并不重要,重要的是需要整理清楚在使用DFS算法思想求解问题时,该如何入手思考问题。
有一些思路还需要在继续思考。
(还没有完全思考清楚)
(完)
</div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-b6c3c6d139.css" rel="stylesheet">
<div class="more-toolbox">
<div class="left-toolbox">
<ul class="toolbox-list">
<li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#csdnc-thumbsup"></use>
</svg><span class="name">点赞</span>
<span class="count">11</span>
</a></li>
<li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{"mod":"popu_824"}"><svg class="icon" aria-hidden="true">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-Collection-G"></use>
</svg><span class="name">收藏</span></a></li>
<li class="tool-item tool-active is-share"><a href="javascript:;" data-report-click="{"mod":"1582594662_002"}"><svg class="icon" aria-hidden="true">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-csdnc-fenxiang"></use>
</svg>分享</a></li>
<!--打赏开始-->
<!--打赏结束-->
<li class="tool-item tool-more">
<a>
<svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg>
</a>
<ul class="more-box">
<li class="item"><a class="article-report">文章举报</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="person-messagebox">
<div class="left-message"><a href="https://blog.csdn.net/seagal890">
<img src="https://profile.csdnimg.cn/D/E/C/3_seagal890" class="avatar_pic" username="seagal890">
<img src="https://g.csdnimg.cn/static/user-reg-year/1x/15.png" class="user-years">
</a></div>
<div class="middle-message">
<div class="title"><span class="tit"><a href="https://blog.csdn.net/seagal890" data-report-click="{"mod":"popu_379"}" target="_blank">梅森上校</a></span>
</div>
<div class="text"><span>发布了597 篇原创文章</span> · <span>获赞 176</span> · <span>访问量 64万+</span></div>
</div>
<div class="right-message">
<a href="https://bbs.csdn.net/topics/395526701" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-messageboard">他的留言板
</a>
<a class="btn btn-sm bt-button personal-watch" data-report-click="{"mod":"popu_379"}">关注</a>
</div>
</div>
</div>