骑士游历算法
2016-03-16 15:26
204 查看
1 骑士游历问题
在国际象棋的棋盘(8行×8列)上放置一个马,按照“马走日字”的规则,马要遍历棋盘,即到达棋盘上的每一格,并且每格只到达一次。若给定起始位置(x0,y0),编程探索出一条路径,沿着这条路径马能遍历棋盘上的所有单元格。
设当前马在棋盘的某个位置(x,y)上,按照规则,下一步有8个方向可走。
设二维数组mat表示棋盘,每个元素表示棋盘的一格,其值定义如下:
0表示马未到达过
Mat[i,j]= -1表示棋盘边界
自然数 表示马到达该格的步数
2 常规的回溯算法
2.1 设计思想
马从棋盘上的某一初始位置(x0,y0)开始,每次选择一个方向k,向前走一格,直到走完64格为止。每走一格,设置数组中相应格的元素值为马走的步数。
如果选择的方向k=0,表示可能的8种走向都试探不通,不通的原因是走向超出了棋盘范围,或当前位置已经被马访问过。此时马已无路可走,说明前几步走得不对,应该退回去重新换一种走法,这种逐步试探的设计思想称为回溯算法。
2.2 性能评价
回溯算法在每一格上朝一个方向盲目地进行试探,遇到在某一格上所有方向都不能走通时,才回到前一格上来试探另一个方向。当每一格上的所有方向都试探过,不能走通时,才做出“走不通”的结论。因此该算法在探索时带有一定的盲目性和随机性,运行效率较低。
3 预见算法
3.1 设计思想
回溯算法的思路是可行的,但它的运行效率较低,原因在于每步试探的随机性和盲目性。如果能够找到一种克服这种随机性和盲目性的办法,按照一定规律选择前进的方向,则将增加成功的可能性,运行时间也大为缩短。本文提出的算法在这方面有所突破。
如果在每步选择方向时,不是任意选择一个方向,而是经过一定的测试和计算,“预见”每条路的“宽窄”,再选择一条最“窄”的路先走,成功的可能性较大。理由是先走“困难的路”,光明大道留在后面。因为每一格迟早都要走到,与其把困难留在后面,不如先走“困难的路”,这样路就会越走越宽,成功的机会就越大。这种方法称为预见算法。
3.2 实现手段
为每个方向测定一个值――可通路数,它表示该位置上还有多少条通路。在每一格上对8个方向都进行试探,并分析比较,下一步应该选择可通路数值最小的方向走。
下面表格是有多少个位置可以到达当前这个位置:
下面上代码
参看文献:
http://www.xzbu.com/8/view-1086965.htm http://www.wuji8.com/meta/266880944.html http://wenku.baidu.com/link?url=kDUHpgB1ZPtk_CDE8l0q_ekArNkRiOPMHBb-YDcNsupACwajBJt2jm3ySyR2D6b7llZdVhnXVRiGhmdfP7-uNUQ7MuaUO3lFZUhFJ4TkE4C
在国际象棋的棋盘(8行×8列)上放置一个马,按照“马走日字”的规则,马要遍历棋盘,即到达棋盘上的每一格,并且每格只到达一次。若给定起始位置(x0,y0),编程探索出一条路径,沿着这条路径马能遍历棋盘上的所有单元格。
设当前马在棋盘的某个位置(x,y)上,按照规则,下一步有8个方向可走。
设二维数组mat表示棋盘,每个元素表示棋盘的一格,其值定义如下:
0表示马未到达过
Mat[i,j]= -1表示棋盘边界
自然数 表示马到达该格的步数
2 常规的回溯算法
2.1 设计思想
马从棋盘上的某一初始位置(x0,y0)开始,每次选择一个方向k,向前走一格,直到走完64格为止。每走一格,设置数组中相应格的元素值为马走的步数。
如果选择的方向k=0,表示可能的8种走向都试探不通,不通的原因是走向超出了棋盘范围,或当前位置已经被马访问过。此时马已无路可走,说明前几步走得不对,应该退回去重新换一种走法,这种逐步试探的设计思想称为回溯算法。
2.2 性能评价
回溯算法在每一格上朝一个方向盲目地进行试探,遇到在某一格上所有方向都不能走通时,才回到前一格上来试探另一个方向。当每一格上的所有方向都试探过,不能走通时,才做出“走不通”的结论。因此该算法在探索时带有一定的盲目性和随机性,运行效率较低。
3 预见算法
3.1 设计思想
回溯算法的思路是可行的,但它的运行效率较低,原因在于每步试探的随机性和盲目性。如果能够找到一种克服这种随机性和盲目性的办法,按照一定规律选择前进的方向,则将增加成功的可能性,运行时间也大为缩短。本文提出的算法在这方面有所突破。
如果在每步选择方向时,不是任意选择一个方向,而是经过一定的测试和计算,“预见”每条路的“宽窄”,再选择一条最“窄”的路先走,成功的可能性较大。理由是先走“困难的路”,光明大道留在后面。因为每一格迟早都要走到,与其把困难留在后面,不如先走“困难的路”,这样路就会越走越宽,成功的机会就越大。这种方法称为预见算法。
3.2 实现手段
为每个方向测定一个值――可通路数,它表示该位置上还有多少条通路。在每一格上对8个方向都进行试探,并分析比较,下一步应该选择可通路数值最小的方向走。
下面表格是有多少个位置可以到达当前这个位置:
2 | 3 | 4 | 4 | 4 | 4 | 3 | 2 |
3 | 4 | 6 | 6 | 6 | 6 | 4 | 3 |
4 | 6 | 8 | 8 | 8 | 8 | 6 | 4 |
4 | 6 | 8 | 8 | 8 | 8 | 6 | 4 |
4 | 6 | 8 | 8 | 8 | 8 | 6 | 4 |
4 | 6 | 8 | 8 | 8 | 8 | 6 | 4 |
3 | 4 | 6 | 6 | 6 | 6 | 4 | 3 |
2 | 3 | 4 | 4 | 4 | 4 | 3 | 2 |
public class Knight { private boolean Travel(int firstX, int firstY, int[][] board) { // 对应骑士可走的8个方向 int[] movex = { -2, -1, 1, 2, 2, 1, -1, -2 }; int[] movey = { 1, 2, 2, 1, -1, -2, -2, -1 }; // 下一步出路的位置 int[] nextStepX = new int[board.length]; int[] nextStepY = new int[board.length]; // 记录出路的个数 int[] exitS = new int[board.length]; int nextX = firstX; int nextY = firstY; board[nextX][nextY] = 1; for (int m = 2; m <= Math.pow(board.length, 2); m++) { //初始化下一个位置可走的位置的数目 for (int i = 0; i < board.length; i++) { exitS[i] = 0; } int count = 0; // 试探8个方向 for (int i = 0; i < 8; i++) { int temI = nextX + movex[i]; int temJ = nextY + movey[i]; // 走到边界,路断 if (temI < 0 || temI > 7 || temJ < 0 || temJ > 7) { continue; } // 记录下可走的方向 if (0 == board[temI][temJ]) { nextStepX[count] = temI; nextStepY[count] = temJ; count++; } } // 到这里,cout表示当前点有几种走法。nextStep中存储各种走法的坐标。 int min = -1; if (count == 0) { return false; } if (1 == count) { min = 0; } else {// 这一步是为了找到下一次走法中最少种走法的那一步 for (int i = 0; i < count; i++) { for (int j = 0; j < 8; j++) { int temI = nextStepX[i] + movex[j]; int temJ = nextStepY[i] + movey[j]; if (temI < 0 || temI > 7 || temJ < 0 || temJ > 7) { continue; } // 记录下这个位置可走的方向数 if (0 == board[temI][temJ]) { exitS[i]++; } } } int tem = exitS[0]; min = 0; // 从可走的方向中,寻找最少走的出路 for (int i = 1; i < count; i++) { if (tem > exitS[i]) { tem = exitS[i]; min = i; } } } // 得到最少的出路 nextX = nextStepX[min]; nextY = nextStepY[min]; board[nextX][nextY] = m; } return true; } public static void main(String[] args) { int firstX, firstY; System.out.println("输入起始点(0-7):"); Scanner scanner = new Scanner(System.in); firstX = scanner.nextInt(); firstY = scanner.nextInt(); int[][] board = new int[8][8]; Knight knight = new Knight(); if (knight.Travel(firstX, firstY, board)) { System.out.println("游历完成:"); } else { System.out.println("游历失败!\n"); } for (int i = 0; i < board.length; i++) { for (int j = 0; j < board[0].length; j++) { if (board[i][j] < 10) { System.out.print(" " + board[i][j]); } else { System.out.print(board[i][j]); } System.out.print(" "); } System.out.println(); } } }
参看文献:
http://www.xzbu.com/8/view-1086965.htm http://www.wuji8.com/meta/266880944.html http://wenku.baidu.com/link?url=kDUHpgB1ZPtk_CDE8l0q_ekArNkRiOPMHBb-YDcNsupACwajBJt2jm3ySyR2D6b7llZdVhnXVRiGhmdfP7-uNUQ7MuaUO3lFZUhFJ4TkE4C
相关文章推荐
- Tomcat(一):基础配置详解
- 不同类型数据间的转换
- linux分析日志 笔记
- SAP 740系统BSEG和BKPF可以直接关联
- java.util.current的主要方法简介
- asp.net 导出Excel
- ASP.NET 项目 App_Code下无法找到类
- java.io.EOFException java.io.ObjectInputStream$PeekInputStream.readFully 错误
- 文章标题
- pku1159 Palindrome DP
- mysql 大对象
- Linux常用命令汇总
- UIImageView 的contentMode属性
- spark编程指南
- java面试知识点三(HashMap输出及保持元素唯一性)
- android 开机动画
- 蓝桥杯 历届试题 连号区间数 解题报告
- 源代码版本管理与项目管理软件的认识与github的注册
- [国嵌攻略][151][nandflash驱动程序设计]
- Oracle学习笔记(四)