标签:解法 return png ISE 优缺点 数字 选择 学习 多个
我们肯定都玩过迷宫游戏吧,比较复杂的迷宫,肯定是不可能第一遍就直接过了,只能一步一步地进行尝试。当走到一个死胡同时,只能退回到上一个分岔口进行重新选择。
数独游戏也是这样的,对于一个不确定的方格,我们就会先将这个方格可能出现的问题记录下来,一个一个地尝试,直到得到正确解。有着“通用解”称呼
所以,回溯算法就是类似于枚举的算法,将这一步的所以可能性一个一个地进行尝试。上边迷宫中的分岔口和数独中的可能出现多个数字的方格就是“回溯点”
八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种计算机语言可以解决此问题。
使用Java来解决此问题主要有以下步骤:
private int result[] = new int[8];
首先想到的就是一个二维数组,但是我在学习的时候,看到老师用了一个长度为8的一维数组就解决了,思想如下:
/**
* 判断这一行中的棋子摆放的是否可用
* 主要就是判断从第一行到第n-1行的这几个皇后会不会和第n行的皇后相互攻击
* 因为之前的n-1行之间之前就已经判断了的,如果它们之前不满足条件就不会到第n行的
*
* @param n 传入的这一行
* @return
*/
private boolean check(int n) {
timeCount++;
for (int i = 0; i < n; i++) {
/*
第一个条件就是判断它们是不是在同一行
这里主要想一个如何判断它们是不是在同一斜行上,
因为我们的模型就是使用数组的角标来表示它当前在第i+1行,用元素表示它在这一行的第i+1个位置上
*/
if (result[i] == result[n] || Math.abs(n - i) == Math.abs(result[n] - result[i])) {
return false;
}
}
return true;
}
4.开始写放置棋子的方法
/**
* 最关键的问题,使用递归来进行回溯算法
* 我们的思路就是一行一行的放置
*
* @param row 在第几行摆放棋子
*/
public void calResult(int row) {
if (row > 7) {
//此时就说明第8行已经摆完了,且是正确的
sum++;
printResult();
return;
}
//这个for循环就是在这一行从第1个开始放,一直放到第max个,
for (int i = 0; i < max; i++) {
result[row] = i;
if (check(row)) {
//说明这一行检验是通过的
calResult(row+1);
}
//如果这个位置不满足,就会自动执行下一次循环,也就是i++
//如果这一行全部试完之后,还是不合格,就会自动放到回溯到上一行去
}
}
最后的代码如下:
package cn.lyn4ever.structure.excerise;
public class EightQueenDemo {
/**
* 用来表示摆放皇后的结果,
* 数组的下标表示第i+1行的棋子,值表示棋子放在这一行的第i+1个位置
* 如:
* result[0]=0 表示在第一行的第一个位置上有一个棋子
*/
private int max = 8;
private int result[] = new int[max];
private int sum = 0;//用来记录总结果数
private int timeCount = 0;//用来记录所有操作的次数
/**
* 判断这一行中的棋子摆放的是否可用
* 主要就是判断从第一行到第n-1行的这几个皇后会不会和第n行的皇后相互攻击
* 因为之前的n-1行之间之前就已经判断了的,如果它们之前不满足条件就不会到第n行的
*
* @param n 传入的这一行
* @return
*/
private boolean check(int n) {
timeCount++;
for (int i = 0; i < n; i++) {
/*
第一个条件就是判断它们是不是在同一行
这里主要想一个如何判断它们是不是在同一斜行上,
因为我们的模型就是使用数组的角标来表示它当前在第i+1行,用元素表示它在这一行的第i+1个位置上
*/
if (result[i] == result[n] || Math.abs(n - i) == Math.abs(result[n] - result[i])) {
return false;
}
}
return true;
}
/**
* 打印这个结果数组
*/
private void printResult() {
for (int i = 0, length = result.length; i < length; i++) {
System.out.print(result[i] + " ");
}
System.out.println();
}
/**
* 最关键的问题,使用递归来进行回溯算法
* 我们的思路就是一行一行的放置
*
* @param row 在第几行摆放棋子
*/
public void calResult(int row) {
if (row > 7) {
//此时就说明第8行已经摆完了,且是正确的
sum++;
printResult();
return;
}
//这个for循环就是在这一行从第1个开始放,一直放到第max个,
for (int i = 0; i < max; i++) {
result[row] = i;
if (check(row)) {
//说明这一行检验是通过的
calResult(row+1);
}
//如果这个位置不满足,就会自动执行下一次循环,也就是i++
//如果这一行会部试完之后,还是不合格,就会自动放到回溯到上一行去
}
}
public static void main(String[] args) {
EightQueenDemo eightQueenDemo = new EightQueenDemo();
eightQueenDemo.calResult(0);
System.out.printf("八皇后问题的解法一共有%d", eightQueenDemo.sum);
System.out.printf("一共进行了%d次运算", eightQueenDemo.timeCount);
}
}
最后的运行结果如下:
标签:解法 return png ISE 优缺点 数字 选择 学习 多个
原文地址:https://www.cnblogs.com/Lyn4ever/p/12181741.html