马踏棋盘(回溯算法)

题目

在n*m的棋盘中,马只能走"日"字。马从位置(x,y)出发,把棋盘的每一格都走一次且只走一次。找出所有路径。 

分析 

马是在棋盘的点上行走的,所以这里的棋盘是指行有N条边、列有M条边。而一个马在不出边界的情况下有8个方向 可以行走(走"日"字),如当前坐标为(x,y),则行走后的坐标可以为: 
     (x+1, y+2) 
     (x+1, y-2) 
     (x+2, y+1) 
     (x+2, y-1) 
     (x-1, y-2) 
     (x-1, y+2) 
     (x-2, y-1) 
     (x-2, y+1) 

     搜索的解空间是整个棋盘上的n*m个点。 
     约束条件是不出边界且每个点只经过一次。 
     搜索过程是从任一点(x,y)出发,按照深度优先的原则,从8个方向中尝试一个可以走的点,直到走过棋盘上所有 n*m个点。

实现

public class RecollectionSearch {

    public static void main(String[] args) {  
        // 注意(0<=x<n && 0<=y<m)  
        int n = 5;  
        int m = 4;  
        int x = 0;  
        int y = 0;  
        RecollectionSearch rs = new RecollectionSearch(n, m, x, y);  
        rs.find(x, y, 2);  
        System.out.println("######################");  
        System.out.println("总解数count=" + rs.getCount());  
        System.out.println("######################");
    }  
  
    // 棋盘行数  
    private int n;  
    // 棋盘列数  
    private int m;  
    // 马的起始x坐标  
    private int x;  
    // 马的起始y坐标  
    private int y;  
    // 棋盘坐标  
    private int[][] a;  
    // 求解总数  
    private int count;  
    // "日"子x坐标  
    public int[] fx = { 1, 2, 2, 1, -1, -2, -2, -1 };  
    // "日"子y坐标  
    public int[] fy = { 2, 1, -1, -2, -2, -1, 1, 2 };  
  
    /** 
     * 构造方法
     */  
    public RecollectionSearch(int _n, int _m, int _x, int _y) {  
        n = _n;  
        m = _m;  
        x = _x;  
        y = _y;  
        a = new int[n][m];  
        for (int i = 0; i < n; i++) {  
            for (int j = 0; j < m; j++) {  
                a[i][j] = 0;  
            }  
        }  
        // 马的起点  
        a[x][y] = 1;  
        count = 0;  
    }  
  
    public void find(int x, int y, int dep) {  
        int i, xx, yy;  
        for (i = 0; i < 8; i++) {  
            xx = x + fx[i];  
            yy = y + fy[i];  
            // 判断新坐标是否出界,是否已走过  
            if (check(xx, yy) == 1) {  
                a[xx][yy] = dep;  
                if (dep == n * m) {  
                    output();  
                } else {  
                    // 从新坐标出发,递归下一层  
                    find(xx, yy, dep + 1);  
                }  
                // 回溯,恢复未走标志  
                a[xx][yy] = 0;  
            }  
        }  
    }  
  
    /** 
     * 判断新坐标是否出界,是否已走过
     */  
    public int check(int xx, int yy) {  
        if (xx >= n || yy >= m || xx < 0 || yy < 0 || a[xx][yy] != 0) {  
            return 0;  
        }  
        return 1;  
    }  
  
    /** 
     * 输出结果 
     */  
    public void output() {  
        count++;  
        System.out.println("count=" + count);  
        for (int y = 0; y < n; y++) {  
            System.out.println("");  
            for (int x = 0; x < m; x++) {  
                System.out.print(a[y][x] + " ");  
            }  
        }  
        System.out.println("");  
    }
  
    public int getCount() {  
        return count;  
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值