回溯法--深度优先搜索
1、概念
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。
2、基本思想
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。
若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。
而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
3、步骤
(1)针对所给问题,确定问题的解空间:
首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。
(2)确定结点的扩展搜索规则
(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
例子:
矩阵中的路径,剑指offer
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如[ab c e s f c s a d e e]是3*4矩阵,其包含字符串"bcced"的路径,但是矩阵中不包含“abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
回溯算法 这是一个可以用回朔法解决的典型题。
首先,在矩阵中任选一个格子作为路径的起点。如果路径上的第i个字符不是ch,那么这个格子不可能处在路径上的第i个位置。如果路径上的第i个字符正好是ch,那么往相邻的格子寻找路径上的第i+1个字符。除在矩阵边界上的格子之外,其他格子都有4个相邻的格子。重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。
由于回朔法的递归特性,路径可以被开成一个栈。当在矩阵中定位了路径中前n个字符的位置之后,在与第n个字符对应的格子的周围都没有找到第n+1个字符,这个时候只要在路径上回到第n-1个字符,重新定位第n个字符。由于路径不能重复进入矩阵的格子,还需要定义和字符矩阵大小一样的布尔值矩阵,用来标识路径是否已经进入每个格子。 当矩阵中坐标为(row,col)的格子和路径字符串中相应的字符一样时,从4个相邻的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路径字符串中下一个字符如果4个相邻的格子都没有匹配字符串中下一个的字符,表明当前路径字符串中字符在矩阵中的定位不正确,
我们需要回到前一个,然后重新定位。一直重复这个过程,直到路径字符串上所有字符都在矩阵中找到合适的位置。
public class Solution {// 选取一个节点(i,j)为起始点,递归遍历这个节点上下左右的元素是否和待匹配的字符数组中元素相同,// 相同则继续遍历这个相同节点的上下左右元素,不同则后退回来。public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {boolean[] visited = new boolean[matrix.length];for (int i = 0; i < rows; i++)for (int j = 0; j < cols; j++)if (hasPathCore(matrix, rows, cols, i, j, str, visited, 0))return true;return false;}/*** @param matrix* 矩阵* @param rows* 矩阵行数* @param cols* 矩阵列数* @param i* 矩阵行数索引* @param j* 矩阵列数索引* @param str* 要查找的目标字符串* @param visited* 对应的boolean矩阵是否访问过* @param index* str字符串的下标,从0开始* @return*/private boolean hasPathCore(char[] matrix, int rows, int cols, int i, int j, char[] str, boolean[] visited,int index) {int idx = i * cols + j;if (i < 0 || j < 0 || i >= rows || j >= cols)return false;if (visited[i * cols + j] || matrix[idx] != str[index])return false;if (index == str.length - 1)return true;// 剪枝 状态位visited[idx] = true;index++;if (hasPathCore(matrix, rows, cols, i + 1, j, str, visited, index)|| hasPathCore(matrix, rows, cols, i, j + 1, str, visited, index)|| hasPathCore(matrix, rows, cols, i - 1, j, str, visited, index)|| hasPathCore(matrix, rows, cols, i, j - 1, str, visited, index))return true;visited[idx] = false;// 此题不index--也通过,why????index--;return false;}
}
机器人的运动范围 ,剑指offer
public class Solution {public int movingCount(int threshold, int rows, int cols) {if (threshold < 1 || rows < 1 || cols < 1) {return 0;}boolean[][] visited = new boolean[rows][cols];return movingCountCore(0, 0, rows, cols, visited, threshold);}private int movingCountCore(int i, int j, int rows, int cols, boolean[][] visited, int threshold) {if (i < 0 || i >= rows || j < 0 || j >= cols)return 0;if (getDigitNum(i) + getDigitNum(j) > threshold || visited[i][j])return 0;visited[i][j] = true;// 标记访问过,这个标志visited不需要回溯,因为只要被访问过即可。// 因为如果能访问,访问过会加1.不能访问,也会标记下被访问过。return movingCountCore(i - 1, j, rows, cols, visited, threshold)+ movingCountCore(i + 1, j, rows, cols, visited, threshold)+ movingCountCore(i, j - 1, rows, cols, visited, threshold)+ movingCountCore(i, j + 1, rows, cols, visited, threshold)+ 1;}private int getDigitNum(int num) {int sum = 0;while (num > 0) {sum += num % 10;num /= 10;}return sum;}
}
AutoPilot01(去哪儿2017校招真题)
自动驾驶技术这个词因Tesla为人们所熟悉,殊不知tesla仍只是处于非常初级辅助阶段,然而Uber与Volvo已经开始在匹兹堡试验部署真正意义的自动驾驶汽车,原理是在构建好的复杂地图数据基础上,根据在车辆移动时通过GPS结合车上的数个传感器、立体摄像头以及激光雷达收集数据与地图数据比对以此来识别交通标志、行人和障碍物并选择合适的道路自动讲乘客从A点带到B点。假设我们将地图抽象成一个N x N的二维矩阵,0为可行驶道路1为障碍物,车辆只能一步步按东、南、西、北方向行驶,请输出从A点[0,0]至B点[n-1,n-1]的最少步数(移动一次计一步)。
输入
一共n行,每行n个整数(空格分隔),只可能为0或1
输出
输出最短距离步数,不可到达则输出-1
样例输入
0 1 0 0
0 0 0 1
1 0 1 0
0 0 0 0
样例输出
6
import java.util.Scanner;
public class Main {private static int min = 0;private static int temp = 0;public static void main(String[] args) {Scanner sc = new Scanner(System.in);while (sc.hasNext()) {String str = sc.nextLine();String strs[] = str.split("\\s+");int count = strs.length;int[][] arr = new int[count][count];for (int i = 0; i < count; i++)arr[0][i] = Integer.parseInt(strs[i]);for (int i = 1; i < count; i++) {for (int j = 0; j < count; j++) {arr[i][j] = sc.nextInt();}}search(arr, 0, 0);if (min == 0) {System.out.println(-1);} else {System.out.println(min);}}}private static void search(int[][] arr, int row, int col) {if (row >= arr.length || col >= arr.length || row < 0 || col < 0)return;if (row == arr.length - 1 && col == arr.length - 1) {if (min == 0)min = temp;if (temp < min)min = temp;return;}if (arr[row][col] == 0) {temp++;arr[row][col] = 1;search(arr, row - 1, col);search(arr, row + 1, col);search(arr, row, col - 1);search(arr, row, col + 1);temp--;arr[row][col] = 0;}}
}
AutoPilot02(去哪儿2017校招真题)
自动驾驶技术这个词因Tesla为人们所熟悉,殊不知tesla仍只是处于非常初级辅助阶段,然而Uber与Volvo已经开始在匹兹堡试验部署真正意义的自动驾驶汽车,原理是在构建好的复杂地图数据基础上,根据在车辆移动时通过GPS结合车上的数个传感器、立体摄像头以及激光雷达收集数据与地图数据比对以此来识别交通标志、行人和障碍物并选择合适的道路自动讲乘客从A点带到B点。假设我们将地图抽象成一个N x N的二维矩阵,0为可行驶道路1为障碍物,车辆只能一步步按东、南、西、北方向行驶,请编程找出一条从A点[0,0]至B点[n-1,n-1]的最短路径。
输入
一共n行,每行n个整数(空格分隔),只可能为0或1
输出
输出最短路径,不可到达则输出nopath
样例输入
0 1 0 0
0 0 0 1
1 0 1 0
0 0 0 0
样例输出
0,0
1,0
1,1
2,1
3,1
3,2
3,3
此题过了百分之83,但是不知道错误在哪里,思想是根据求出所有路径,然后找到符合要求的路径,和二叉树路径差不多
class Node {public int row;public int col;public Node(int row, int col) {this.row = row;this.col = col;}@Overridepublic String toString() {return row + "--" + col;}
}
public class Main{public static ArrayList<ArrayList<Node>> ret = new ArrayList<ArrayList<Node>>();public static ArrayList<Node> tep = new ArrayList<Node>();public static void main(String[] args) {Scanner sc = new Scanner(System.in);while (sc.hasNext()) {String str = sc.nextLine();String strs[] = str.split("\\s+");int count = strs.length;long[][] arr = new long[count][count];for (int i = 0; i < count; i++)arr[0][i] = Integer.parseInt(strs[i]);for (int i = 1; i < count; i++) {for (int j = 0; j < count; j++) {arr[i][j] = sc.nextInt();}}search(arr, 0, 0);ArrayList<Node> list = null;for (ArrayList<Node> l : ret)if (l.get(l.size() - 1).row == count - 1 && l.get(l.size() - 1).col == count - 1) {if (list == null)list = l;else if (list.size() > l.size())list = l;}if (list == null)System.out.println("nopath");else {for (Node node : list)System.out.println(node.row + "," + node.col);}// System.out.println(ret);}}private static void search(long[][] arr, int row, int col) {if (row >= arr.length || col >= arr.length || row < 0 || col < 0) {ret.add(new ArrayList<Node>(tep));return;}if (row <= arr.length - 1 && col <= arr.length - 1) {tep.add(new Node(row, col));}if (arr[row][col] == 0) {arr[row][col] = 1;search(arr, row + 1, col);search(arr, row, col + 1);search(arr, row - 1, col);search(arr, row, col - 1);arr[row][col] = 0;}tep.remove(tep.size() - 1);}
}
概念参考:http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741376.html
回溯法--深度优先搜索相关推荐
- 基于深度优先搜索回溯法的人狼羊菜过河模型
基于深度优先搜索回溯法的人狼羊菜过河模型 本文介绍一个农夫过河的小模型,算法 Python 实现,感觉还挺有趣的,因原为笔者课程作业论文改版而来,所以文章内容比起其他博客文章可能会比较严肃与严谨.期待 ...
- 回溯法(深度优先)剪枝和分支限界法(宽度优先)剪枝对比:01背包问题
限界函数: CurValue + rest <= BestValue 回溯法(深度优先)剪枝 # 递归方式 class pack_01_back_prune_test: def __init__ ...
- 图:邻接矩阵表示法创建无向图并深度优先搜索遍历
无向图样式: 邻接矩阵法类似于用数组储存,一个一维数组储存顶点信息,还有一个二维数组储存邻接矩阵 用邻接矩阵进行无向图的创建过程: 一,输入总顶点数和边数(几个点,几条边) eg:如图所示即为8点,9 ...
- c语言中穷竭算法,hihocoder#1054 : 滑动解锁(深度优先搜索)
描述 滑动解锁是智能手机一项常用的功能.你需要在3x3的点阵上,从任意一个点开始,反复移动到一个尚未经过的"相邻"的点.这些划过的点所组成的有向折线,如果与预设的折线在图案.方向上 ...
- 使用回溯法解决编辑距离问题(C语言)
回溯法 应用回溯法时,解空间往往以树的结构表示.回溯法以深度优先的方式搜索解空间树.如果回溯法在执行过程中判断解空间树的某个节点不包含问题的解时,则跳过对以该节点为根的子树的搜索,逐层向其祖先节点回溯 ...
- 回溯法 -数据结构与算法
1.回溯法算法思想: 定义: 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术 ...
- 算法笔记之回溯法(一)——溯洄从之,道阻且长;溯游从之,宛在水中央。
回溯法理论基础 回溯法是一种搜索算法,从本质上来说,回溯法是一种穷举法,穷尽其所有可能而举其可行解:尽管回溯法有剪枝等操作,但也只是去除一些明显不可行的部分,仍改变不了回溯法暴力搜索的本质. 虽然回溯 ...
- 数据结构—回溯法、子集树、排列树
文章目录 回溯法 问题的解空间 递归回溯 迭代回溯 子集树与排列树简单介绍 轮船装载问题 0-1背包问题 八皇后问题 整数求和(1) 整数求和(2) 全排列 回溯法 回溯法是一种以深度优先方式系统搜索 ...
- 算法分析五:回溯法与分⽀限界法
一.回溯法 1. 基本思想与解题步骤 基本思想: 把问题的解空间转化成了图或者树的结构表⽰,然后使⽤深度优先搜索策略进⾏遍历,遍历的过程中记录和寻找所有可⾏解或者最优解. 解题步骤: 针对所给问题,定 ...
最新文章
- 批量自动外呼带来的效益
- mysql数据库的打开失败_MySQL数据库启动失败解决
- 將軍苑 - 收藏集 - 掘金
- veket智能机器人
- php改密后joomla无法登陆,php – Joomla 3.3禁用“重置密码”功能
- iPad开发(相对于iPhone开发时专有的API)
- 基于WF4的新平台-流程模式-(9)表单路由启动传入
- Qt公有槽和私有槽的区别
- 基于VxWorks的VxBus字符设备驱动
- matlab 矩阵数据类型,Matlab数据类型
- 虚拟化技术的优点和缺点
- Java毕设项目超市进销存管理系统计算机(附源码+系统+数据库+LW)
- java 取上界_Java中的上界通配符 - java
- 采集rtsp流摄像头到浏览器实时播放方案
- Node rar压缩/解压文件
- 利用Pytorch实现ResNeXt网络
- SSM框架:Spring
- 1800个python编程入门必备英语词汇_1800个程序员常用英语词汇,编程入门的前提!PDF电子版限时免费...
- Linux英文环境下登陆Chrome印象笔记插件
- topwin耳塞使用方法_如何使Windows PC使用“单声道”音频(因此您可以戴一副耳塞)...