知识的学习在于点滴记录,坚持不懈;知识的学习要有深度和广度,不能只流于表面,坐井观天;知识要善于总结,不仅能够理解,更知道如何表达!
排列树
解空间就是问题所有解的可能取值构成的空间,一个问题的解往往包含了得到这个解的每一步,就是对应解空间树中一条从根节点到叶子节点的路径。
排列树就代表了一类问题的解空间,它并不是真实存在的数据结构,也就是说并不是真的有一颗这样的树,只是抽象出来的解的空间树。
当问题求解的结果是集合S的元素的某一种排列的时候,其对应的解空间就是排列树,时间复杂度是 O ( n ! ) O(n!) O(n!),同样可以通过适当的剪枝函数来提供排列树的遍历效率。代码示例如下:
public static void main(String[] args) {
int[] arr = {1,2,3};
backtrace(arr, 0, arr.length);
}
private static void swap(int[] arr, int i, int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
private static void backtrace(int[] arr, int i, int length) {
if(i == length){
System.out.println(Arrays.toString(arr));
} else {
for (int j = i; j < length; j++) {
swap(arr, i, j);
backtrace(arr, i+1, length);
swap(arr, i, j);
}
}
}
这段代码运行的结果,其结果就构成了一颗排列树,如下图所示:
手写八皇后问题代码
还记得是2018届的一位理工同学,和邮电的几位同学一起,去面试某某世界的时候,在面试最后有一个代码题需要输出,邮电的同学写的都是一个简单的双链表的删除,而到他就是手写八皇后问题的代码,感觉十分崩溃,也因为那时候没有给大家上这一部分的内容,其实八皇后的问题,只要理解了排列树这个解空间的生成过程,其代码是非常简单的。
八皇后问题:按照国际象棋规则,皇后可以攻击与之处在同一行,或者同一列,或者同一斜线上的其它棋子。现在有n个皇后放置在nxn格的棋盘上,如何摆放n个皇后而使它们都不能互相吃子?有多少种摆法?
八皇后问题,实际上就是要求输出对原序列元素的一种特殊的排列方式,实现代码如下:
public class Queen {
public static void main(String[] args) {
// 数组元素下标代表行数,元素内容代表列数,表示皇后棋子放至的行列数
int[] arr = {1,2,3,4,5,6,7,8};
backtrace(arr, 0, arr.length);
System.out.println("总的排列数:" + count);
}
private static void swap(int[] arr, int i, int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
static int count = 0; // 记录一下总的排列数
private static void backtrace(int[] arr, int i, int length) {
if(i == length){
count++;
System.out.println(Arrays.toString(arr));
} else {
for (int j = i; j < length; j++) {
swap(arr, i, j);
if(line(arr, i)){
backtrace(arr, i+1, length);
}
swap(arr, i, j);
}
}
}
private static boolean line(int[] arr, int i) {
// 检查从第0行开始,到第i行,不能出现同行i==j,同列arr[i]==arr[j],同斜线的棋子
for (int j = 0; j < i; j++) {
if(i == j && arr[i] == arr[j]
&& Math.abs(arr[i] - arr[j]) == Math.abs(i - j)){
return false;
}
}
return true;
}
}
运行上面的代码,可以看出结果,总共是92种摆法。