//给你一个大小为 m x n 的网格和一个球。球的起始坐标为 [startRow, startColumn] 。你可以将球移到在四个方向上相邻的单元格内（可以
//穿过网格边界到达网格之外）。你 最多 可以移动 maxMove 次球。 
//
// 给你五个整数 m、n、maxMove、startRow 以及 startColumn ，找出并返回可以将球移出边界的路径数量。因为答案可能非常大，返回对 
//109 + 7 取余 后的结果。 
//
// 
//
// 示例 1： 
//
// 
//输入：m = 2, n = 2, maxMove = 2, startRow = 0, startColumn = 0
//输出：6
// 
//
// 示例 2： 
//
// 
//输入：m = 1, n = 3, maxMove = 3, startRow = 0, startColumn = 1
//输出：12
// 
//
// 
//
// 提示： 
//
// 
// 1 <= m, n <= 50 
// 0 <= maxMove <= 50 
// 0 <= startRow < m 
// 0 <= startColumn < n 
// 
// Related Topics 动态规划 
// 👍 190 👎 0

package leetcode.editor.cn;

//576:出界的路径数
class OutOfBoundaryPaths {
    public static void main(String[] args) {
        //测试代码
        Solution solution = new OutOfBoundaryPaths().new Solution();
    }

    //力扣代码
    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {

        // 四个方向
        int[][] dirs = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        // 取余
        int MOD = 1000000007;

        public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
            // 缓存
            int[][][] memo = new int[m][n][maxMove + 1];
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    for (int k = 0; k <= maxMove; k++) {
                        memo[i][j][k] = -1;
                    }
                }
            }
            return dfs(m, n, maxMove, startRow, startColumn, memo);
        }

        private int dfs(int m, int n, int moveCount, int i, int j, int[][][] memo) {
            // 越界了就找到了一条路径
            if (i < 0 || j < 0 || i >= m || j >= n) {
                return 1;
            }

            // 没有移动次数了，返回0
            if (moveCount == 0) {
                return 0;
            }

            // 缓存中存在
            if (memo[i][j][moveCount] != -1) {
                return memo[i][j][moveCount];
            }

            // 剪枝：如果小球不管怎么移动都无法越出网格，那就剪掉这个枝
            if (i - moveCount >= 0 && j - moveCount >= 0 && i + moveCount < m && j + moveCount < n) {
                return 0;
            }

            // 从这个点出发的符合条件的路径数量
            int sum = 0;
            for (int[] dir : dirs) {
                // 记得取余
                sum = (sum + dfs(m, n, moveCount - 1, i + dir[0], j + dir[1], memo)) % MOD;
            }

            // 记录缓存
            memo[i][j][moveCount] = sum;

            return sum;
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}