回溯算法
也称试探法,一种系统地搜索问题的解的算法。其基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试(类似穷举法)。
还记得中学时代的排列组合吗?太像了。
废话就不多说了看题估计就明白了,大概叙述一下昨天一家游戏公司的机试题:
骑士巡游:在一个8X8的格子中,骑士从任意一个格子出发,只能左、右、上、下走,走遍全部格子(不能重复走走过的格子),一共有多少种走法?
个人思路:
- 首先、定义一个二维boolean数组变量boolean[][] pan,走法总数solution_nums;对应值作为判断是否骑士走过该格子,一开始设定为false(全部没走过),然后每走过一个格子便设定其值为true。当走完一次完整的64个格子之后将走法总数+1;
- 其次,定义方法goNext(),即骑士即将走的格子,当然需要判断骑士是否越位,格子是否走过了以及判断是否已经走完所有格子了;
- 最后,当然是入口了,定义入口方法first(),假设开始点是(0,0),则first入口里就需要调用goNext(),根据根据参数判断有向上、向下、向左、向右。
实现代码:
package test.aglorith;
public class Recall {
static int solution_nums=0;
static boolean[][] pan=new boolean[8][8];
//设置入口函数
static void first(int i,int j){
pan[i][j]=true;
//up
goNext(i-1, j, 1);
//down
goNext(i+1, j, 1);
//left
goNext(i, j-1, 1);
//right
goNext(i, j+1, 1);
}
static void goNext(int i,int j,int nums){
//判断是否越界,是否走过
if ((i>=0&i<8) && (j>=0&j<8) && pan[i][j]==false) {
pan[i][j]=true;
nums++;
//判断是否走遍了所有格子
if (nums==64) {
solution_nums++;
System.err.println(solution_nums+"~~");
pan[i][j]=false;
return;
}
//up
goNext(i-1, j, nums);
//down
goNext(i+1, j, nums);
//left
goNext(i, j-1, nums);
//right
goNext(i, j+1, nums);
//做好扫尾工作,擦除走过的轨迹
pan[i][j]=false;
}
}
public static void main(String[] args) {
first(0, 0);//假设从(0,0)点开始
System.err.println(solution_nums);
}
}
时间有点长,以至于一直怀疑自己的算法有问题,可能陷入死循环。如果嫌时间太长,可以将二维数组,判断变量稍微改一下,7X7就需要挺久时间了。
经典的回溯算法中还有三着色,八皇后问题,迷宫问题。
据说这家公司的技术总监14岁就可以做出这道题了。见仁见智。
Have a nice day~