回溯法应用之机器人的运动范围

题目:地上有个m行n列的方格。一个机器人从坐标(0,0)的格子开始移动,它每一次可以向左、右、上、下移动一格,但不能进入行坐标和列坐标的数位之和大于k的格子。


举例分析

  例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7=18.但它不能进入方格(35,38),因为3+5+3+8=19.请问该机器人能够达到多少格子?

解题思路

  和前面的类似,这个方格也可以看出一个m*n的矩阵。同样在这个矩阵中,除边界上的格子之外其他格子都有四个相邻的格子。 
  机器人从坐标(0,0)开始移动。当它准备进入坐标为(i,j)的格子时,通过检查坐标的数位和来判断机器人是否能够进入。如果机器人能够进入坐标为(i,j)的格子,我们接着再判断它能否进入四个相邻的格子(i,j-1)、(i-1,j),(i,j+1)和(i+1,j)。

代码实现

package com.point.offer;

public class qq {
	
	/**
     * 题目:地上有个m行n列的方格。一个机器人从坐标(0,0)的格子开始移动,
     * 它每一次可以向左、右、上、下移动一格,但不能进入行坐标和列坐标的数
     * 位之和大于k的格子。例如,当k为18时,机器人能够进入方格(35,37),
     * 因为3+5+3+7=18.但它不能进入方格(35,38),因为3+5+3+8=19.
     * 请问该机器人能够达到多少格子?
     *
     * @param threshold 约束值
     * @param rows   矩阵行数
     * @param cols   矩阵列数
     * @param str    要搜索的字符串
     * @return 最多可走的方格
     */
	public static int  moveSquare(int threshold, int rows, int cols) {
		//参数校验
		if(threshold < 0 || rows < 1 || cols < 1) {
			return 0;
		}
		//初始化变量 未走过的路径标记为false,走过的路经标记为true
		boolean [] flag = new boolean[rows*cols];
		for (int i = 0; i < flag.length; i++) {
			flag[i] = false;
		}
		return moveSquareCore(threshold, rows, cols, 0, 0, flag);
	}

	/**
     * 递归回溯搜索算法
     *
     * @param threshold 约束值
     * @param rows   矩阵行数
     * @param cols   矩阵列数
     * @param row    当前处理的行号
     * @param col    当前处理的列号
     * @param flag   訪问标记数组
     * @return     最多可走的方格
     */
	private static int moveSquareCore(int threshold, int rows, int cols, int row, int col, boolean[] flag) {
		int count = 0;
		
		if (check(threshold, rows, cols, row, col, flag)) {
			flag[row * cols + col] = true;
			// 按左上右下进行回溯	
			count = 1 + moveSquareCore(threshold, rows, cols, row, col - 1, flag)
					  + moveSquareCore(threshold, rows, cols, row - 1, col, flag)
					  + moveSquareCore(threshold, rows, cols, row, col + 1, flag)
					  + moveSquareCore(threshold, rows, cols, row + 1, col, flag);
		}
		return count;
	}

	 /**
     * 断机器人能否进入坐标为(row, col)的方格
     *
     * @param threshold 约束值
     * @param rows      方格的行数
     * @param cols      方格的列数
     * @param row       当前处理的行号
     * @param col       当前处理的列号
     * @param flag   访问标记数组
     * @return 是否可以进入,true是,false否
     */
	private static boolean check(int threshold, int rows, int cols, int row, int col, boolean[] flag) {
		return row >= 0 && row < rows && col >=0 && col < cols && !flag[row*cols + col] && (getDigitSum(row) + getDigitSum(col) <= threshold);
	}

	/**
	 * 计算一个数字的位数之和
	 *
	 * @param number
	 * @return
	 */
	private static int getDigitSum(int number) {
		int reault = 0;
		while(number > 0) {
			reault += number%10;
			number /= 10;
		}
		return reault;
	}

	 public static void main(String[] args) {
	        System.out.println(moveSquare(5, 10, 10) + "[21]");
	        System.out.println(moveSquare(15, 20, 20) + "[359]");
	        System.out.println(moveSquare(10, 1, 100) + "[29]");
	        System.out.println(moveSquare(10, 1, 10) + "[10]");
	        System.out.println(moveSquare(15, 100, 1) + "[79]");
	        System.out.println(moveSquare(15, 10, 1) + "[10]");
	        System.out.println(moveSquare(5, 10, 10) + "[21]");
	        System.out.println(moveSquare(12, 1, 1) + "[1]");
	        System.out.println(moveSquare(-10, 10, 10) + "[0]");
	    }
	
}  

猜你喜欢

转载自blog.csdn.net/yongwan5637/article/details/80027436
今日推荐