408算法练习——马走日
马走日
一、题目描述
假设国际象棋棋盘有5*5共25个格子,设计一个程序,使棋子从初始位置(如图)开始跳马,需要将棋盘格子全走一遍,每个格子只允许走一次,马的走法只能走“日字形”

问:有多少解
二、解题思路
采用回溯法依次试探下一步的走法,如果下一步走法不合理就不再继续而转向上一步走法。
基本思想:构造一颗树,这个树包含了所有可能的走法(包括合法和不合法的),然后对树进行深度优先搜索,搜索过程中对于每一个结点判断当前结点的走法是否合法,如果合法就进行下去,如果不合法就返回到父节点转向其他子树。
构造一个二维数组,A[5][5],其中A[i][j]中记录了棋盘第i行第j列是否被走过,马当前位置为h行l列,那么马的可能走法就有[h+2][l+1];[h+2][l-1];[h-2][l+1];[h-2][l-1];[h+1][l+2];[h-1][l+2];[h+1][l-2];[h-1][l-2],如图有8种走法,为了方便就假设数组下标从1开始,那么当h和l进行减法或加法运算后如果值小于等于0或大于5都是不合法的。

设计回溯算法,递归边界,可以定义一个计数器count,每次跳马,count++,不能跳马的情况有h和l更新后A[h+1][l+2]或者其他值为1,说明走过这个格子,不能往这里跳。h和l越界也不能跳,如果在某个状态下,不能跳马,而且此时count不是25那么就说明这个方案不可行,就该舍弃,如果count达到25,那么说明这个方案可行。
代码:
1 #include <cstdio> 2 int A[5][5];//用来记录该格子是否被走过 3 const int next[8][2] = {{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}}; 4 int x,y,res=0;//统计所有可能的走法 5 bool check(int x,int y){ 6 if(x>4||x<0||y>4||y<0){//如果发生越界说明此次不合法 7 return false; 8 } 9 if(A[x][y] == 1){//等于1说明这个格子走过了 10 return false; 11 } 12 return true; 13 } 14 void dfs(int x,int y,int count){ 15 if (count == 25){ 16 res++; 17 return; 18 } 19 for(int i=0;i<8;i++){ 20 int next_x = x+next[i][0]; 21 int next_y = y+next[i][1]; 22 if(check(next_x,next_y)){ 23 A[next_x][next_y] = 1; 24 dfs(next_x,next_y,count+1); 25 A[next_x][next_y] = 0;//在进行过判断后将A数组改回来用于下一次遍历,注意理解这行代码,该行为关键行 26 } 27 } 28 } 29 30 int main(){ 31 A[0][0] = 1; 32 dfs(0,0,1); 33 printf("%d",res); 34 return 0; 35 }
最终结果为304

浙公网安备 33010602011771号