【回溯】有蹩脚的马踏棋盘——思路巨清晰!!!

本文介绍了一种解决马在棋盘上遍历问题的方法,考虑到棋盘上已有部分位置被占据,通过回溯剪枝算法寻找所有可能的路径。若存在可行路径则输出路径,否则返回无法遍历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

在上一个问题的基础上,如果事先将棋盘中设置有的地方已经被占据,马跳的过程中可能被别脚,如果马能够跳完剩下的棋盘,则遍历输出路径,如果不能跳完,则打印“没有找到全遍历路径”

输入

输入的第一行包含一个正整数n(n< =100)。
第二行为一个小于n * n的整数m。
接下来m行都包含两个整数,每一行代表第i行,第j列的位置已经有棋子。
接下来一行包含两个数,代表起点。

输出

马的遍历路径或者“没有找到全遍历路径。


解法:回溯剪枝

思路

(1)思路同上一题目一样,区别在于判断下一个位置是否可行的条件需要改变
(2)此题需要增加是否被别脚的情况,如果被别脚,则往回跳,继续向其他方向试探

代码
import java.util.Scanner;

/**
 * 象棋中马的轨迹(有别脚)
 *
 * @author Administrator
 *
 */
public class HoursePlus {

    /* 存储棋盘 */
    static int[][] arr;
    /* 棋盘的宽度 */
    static int n;
    /* 别脚的个数 */
    static int m;
    /* 马跳棋盘的8个方向 */
    static int[][] dir = { { -1, -2 }, { -1, 2 }, { -2, 1 }, { -2, -1 },
            { 1, 2 }, { 1, -2 }, { 2, -1 }, { 2, 1 } };

    public static void main(String[] args) {
        @SuppressWarnings("resource")
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        arr = new int[n][n];
        m = scanner.nextInt();
        for (int k = 0; k < m; k++) {
            int i = scanner.nextInt();
            int j = scanner.nextInt();
            // 已经被占据的位置用-1表示
            arr[i][j] = -1;
        }
        int startI = scanner.nextInt();
        int startJ = scanner.nextInt();
        // 马开始跳的起点
        arr[startI][startJ] = 1;
        findPath(startI, startJ, 2);
        System.out.println("没有找到全遍历路径");
    }

    /**
     * 在棋盘中寻找马是否有可行路径,有则打出一个
     *
     * @param startI
     * @param startJ
     */
    private static void findPath(int startI, int startJ, int num) {
        // 停止条件:已经遍历剩余的整个棋盘
        if (num == n * n - m + 1) {
            dispaly(arr);
            System.exit(0);
        } else {
            for (int k = 0; k < 8; k++) {
                int ii = startI + dir[k][0];
                int jj = startJ + dir[k][1];
                // 判断下一位置是否可行
                if(judge(ii, jj, startI, startJ)){
                    // 走过这里标记
                    arr[ii][jj] = num;
                    findPath(ii, jj, num + 1);
                    // 走过,但是路径走不通,马跳回来,取消这里的标记
                    arr[ii][jj] = 0;
                }
            }

        }

    }

    private static boolean judge(int ii, int jj, int i, int j) {
        int b1 = ii - i > 0 ? 1 : -1;
        int b2 = jj - j > 0 ? 1 : -1;
        // 别脚的位置
        i += b1;
        j += b2;
        // 判断别脚是否有棋子
        if(i >= 0 && i < n && j >= 0 && j < n){
            if(arr[i][j] == -1){
                return false;
            }
        }
        // 判断下一个位置是否已经被跳过
        if(ii >= 0 && ii < n && jj >= 0 && jj < n){
            if(arr[ii][jj] == 0){
                return true;
            }
        }
        return false;
    }

    /**
     * 遍历输出
     * @param arr
     */
    private static void dispaly(int[][] arr) {
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                System.out.printf("%3d", arr[i][j]);
            }
            System.out.println();
        }
        System.out.println();
    }

}
运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值