递归和回溯密不可分,可以把递归的过程就是回溯的过程。其中BFS,DFS等经典问题都是与递归和回溯的思想紧密相关的。我们可以不用纠结于每个问题的标签,只要能运用相关的思想解决问题即可。下边,来讨论一下回溯和递归的经典算法问题:n皇后问题。
问题描述:
我们可以把此问题看成递归图:
此题关键是:如何判断冲突。也就是列,对角冲突
Java实现的代码如下:
package com.algorithm;
import java.util.ArrayList;
import java.util.List;
/**
* @Description: n皇后问题
* @author: Jingzeng Wang
* @Date: Created in 18:41 2017/12/13.
*/
public class NQueen {
// 保存全部结果
static List<List<String>> reslut = new ArrayList<>();
// 下边的集合完全可以用数组来替代,如果知道n的话。将n放在外部即可。
// 保存列是否冲突. 若i列放置了就置其为true
static List<Boolean> col = new ArrayList<>();
// 保存对角是否冲突 规律 行+列 0 -- (n-1) 用来判断对角线是否有冲突
static List<Boolean> dia1 = new ArrayList<>();
// 保存对角是否冲突 规律 列-行 -(n-1) -- (n-1) 用来判断对角线是否有冲突
static List<Boolean> dia2 = new ArrayList<>();
public static void main(String[] args) {
// n皇后
int n = 11;
// 初始化集合
for (int i = 0; i < n; i++) {
col.add(false);
}
// 对角线数 2*n-1
for (int i = 0; i < 2 * n - 1; i++) {
dia1.add(false);
dia2.add(false);
}
// 保存每次的结果
List<Integer> res = new ArrayList<>();
generateQueen(n, 0, res);
printResult(n);
}
/**
* 递归回溯求解n皇后
*
* @param n n皇后
* @param index 第index行
* @param res 保存一次搜索结果
*/
private static void generateQueen(int n, int index, List res) {
if (index == n) {
reslut.add(formatResult(n, res));
return;
}
// 遍历每一列可放置的位置
for (int i = 0; i < n; i++) {
// 判断列,对角线,是否可进行放置
if (!col.get(i) && !dia1.get(i + index) && !dia2.get(index - i + n - 1)) {
res.add(i);
col.set(i, true);
dia1.set(i + index, true);
dia2.set(index - i + n - 1, true);
// 递归寻找下一行
generateQueen(n, index + 1, res);
// 遍历完i列的可能结果后,回溯状态,继续下一列
col.set(i, false);
dia1.set(i + index, false);
dia2.set(index - i + n - 1, false);
res.remove(res.size() - 1);
}
}
return;
}
/**
* 格式化结果
*
* @param n
* @param res
* @return
*/
private static List<String> formatResult(int n, List res) {
List<String> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
StringBuffer sb = new StringBuffer();
for (int j = 0; j < n; j++) {
if ((int) res.get(i) == j) {
sb.append("Q ");
continue;
}
sb.append(". ");
}
list.add(sb.toString());
}
return list;
}
/**
* 打印结果
*
* @param n
*/
private static void printResult(int n) {
int count = 1;
for (List<String> singleRes : reslut) {
System.out.println(count++);
for (String s : singleRes) {
System.out.println(s);
}
System.out.println();
}
System.out.println(n + "皇后问题,共" + (count - 1) + "种结果!");
}
}