回溯算法定义:
回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。
回溯算法思想描述:
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。 若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
解题步骤:
1.定义一个解空间,它包含问题的解;
2.利用适于搜索的方法组织解空间;
3.利用深度优先法搜索解空间;
4.利用限界函数避免移动到不可能产生解的子空间。
回溯算法的使用
八皇后
问题描述:
在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
/** * 八皇后 * Created by MGL on 2017/2/23. */
public class EightQueens01 {
public static void main(String[] args) {
EightQueens01 eightQueens01 = new EightQueens01();
eightQueens01.search();
}
/** * 初始化 */
public void search() {
//横向同一栏是否有皇后,1表示有
int[] column = new int[9];
//右上至左下是否有皇后
int[] rup = new int[17];
//左上至右下是否有皇后
int[] lup = new int[17];
//储存保存的皇后的位置(如queen[1] = 3)
//代表在第一行的第三个位置有个皇后
int[] queen = new int[9];
System.out.println(search(1, column, rup, lup, queen, 0));
}
/** * 进行查找 * @param i 第几行 * @param column 横向同一栏是否有皇后,1表示有 * @param rup 右上至左下是否有皇后 * @param lup 左上至右下是否有皇后 * @param queen 答案 * @param count 当前解的个数 * @return */
private int search(int i, int[] column, int[] rup, int[] lup, int[] queen, int count) {
if (i > 8) {
return show(count, queen);
} else {
for (int j = 1; j <= 8; j++) {
//判断同一横栏是否有皇后
//判断右上至左下是否有皇后 判断左上至右下是否有皇后
if ((column[j] == 0) && (rup[i + j] == 0) && (lup[i - j + 8] == 0)) {
//保存结果
queen[i] = j;
column[j] = rup[i + j] = lup[i - j + 8] = 1;
//跳到下一行继续探索
count = search(i + 1, column, rup, lup, queen, count);
column[j] = rup[i + j] = lup[i - j + 8] = 0;
}
}
}
return count;
}
/** * 打印皇后结果 * @param count * @param queen * @return */
private int show(int count, int[] queen) {
count++;
System.out.println("\n解答" + count);
for (int y = 1; y <= 8; y++) {
for (int x = 1; x <= 8; x++) {
if (queen[y] == x) {
System.out.print("Q");
} else {
System.out.print(".");
}
}
System.out.print("\n");
}
return count;
}
}
矩阵中的路径
问题描述:
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。 例如[a b c e s f c s a d e e]是3*4矩阵,其包含字符串”bcced”的路径,但是矩阵中不包含“abcb”路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
//矩阵中每一个格子作为路径的起点
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int[] flag = new int[matrix.length];
if (hasPath(matrix, rows, cols, str, i, j, 0, flag)) {
return true;
}
}
}
return false;
}
/** * 查找 * * @param matrix 使用以为座标储存二维座标的数据 * @param rows 该二维数组有多少行 * @param cols 该二维数组有多少列 * @param str 要查找的路径 * @param i 当前的横座标 * @param j 当前的纵座标 * @param k 查找的次数 * @param flag 经过的座标(经过之后设置为1) * @return */
private boolean hasPath(char[] matrix, int rows, int cols, char[] str, int i, int j, int k, int[] flag) {
//计算当前座标在一维数组中的位置
int index = cols * i + j;
//判断 计算的位置是否越界 判断横座标纵座标是否越界
//判断是否曾经经过座标 判断是否相等
if (index >= matrix.length || i < 0 || j < 0 || i > rows || j > cols || flag[index] == 1 || matrix[index] != str[k]) {
return false;
}
if (k == str.length - 1) {
return true;
}
if (matrix[index] == str[k]) {
flag[index] = 1;
//向左查找
return hasPath(matrix, rows, cols, str, i, j - 1, k + 1, flag) ||
//向下查找
hasPath(matrix, rows, cols, str, i + 1, j, k + 1, flag) ||
//向右查找
hasPath(matrix, rows, cols, str, i, j + 1, k + 1, flag) ||
//向上查找
hasPath(matrix, rows, cols, str, i - 1, j, k + 1, flag);
}
return false;
}
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.hasPath("ABCESFCSADEE".toCharArray(), 3, 4,
"ABCCED".toCharArray()) + "[true]");// true
//ABCE //SEE
//SFCS
//ADEE
System.out.println(solution.hasPath("ABCESFCSADEE".toCharArray(), 3, 4,
"SEE".toCharArray()) + "[true]");// true
//ABCE //ABCB
//SFCS
//ADEE
System.out.println(solution.hasPath("ABCESFCSADEE".toCharArray(), 3, 4,
"ABCB".toCharArray()) + "[false]");// false
//ABCEHJIG //SLHECCEIDEJFGGFIE
//SFCSLOPQ
//ADEEMNOE
//ADIDEJFM
//VCEIFGGS
System.out.println(solution.hasPath("ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS".toCharArray(), 5, 8,
"SLHECCEIDEJFGGFIE".toCharArray()) + "[true]");// true
//ABCEHJIG //SGGFIECVAASABCEHJIGQEM
//SFCSLOPQ //
//ADEEMNOE
//ADIDEJFM
//VCEIFGGS
System.out.println(solution.hasPath("ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS".toCharArray(), 5, 8,
"SGGFIECVAASABCEHJIGQEM".toCharArray()) + "[true]");// true
//ABCEHJIG //SGGFIECVAASABCEEJIGOEM
//SFCSLOPQ
//ADEEMNOE
//ADIDEJFM
//VCEIFGGS
System.out.println(solution.hasPath("ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS".toCharArray(), 5, 8,
"SGGFIECVAASABCEEJIGOEM".toCharArray()) + "[false]");// false
//ABCEHJIG //SGGFIECVAASABCEHJIGQEMS
//SFCSLOPQ
//ADEEMNOE
//ADIDEJFM
//VCEIFGGS
System.out.println(solution.hasPath("ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS".toCharArray(), 5, 8,
"SGGFIECVAASABCEHJIGQEMS".toCharArray()) + "[false]");// false
//AAAA //AAAAAAAAAAAA
//AAAA
//AAAA
System.out.println(solution.hasPath("AAAAAAAAAAAA".toCharArray(), 3, 4,
"AAAAAAAAAAAA".toCharArray()) + "[true]");// true
//AAAA //AAAAAAAAAAAAA
//AAAA
//AAAA
System.out.println(solution.hasPath("AAAAAAAAAAAA".toCharArray(), 3, 4,
"AAAAAAAAAAAAA".toCharArray()) + "[false]");// false
}
}