741. 摘樱桃

一个N x N的网格(grid) 代表了一块樱桃地,每个格子由以下三种数字的一种来表示:

0 表示这个格子是空的,所以你可以穿过它。
1 表示这个格子里装着一个樱桃,你可以摘到樱桃然后穿过它。
-1 表示这个格子里有荆棘,挡着你的路。
你的任务是在遵守下列规则的情况下,尽可能的摘到最多樱桃:

从位置 (0, 0) 出发,最后到达 (N-1, N-1) ,只能向下或向右走,并且只能穿越有效的格子(即只可以穿过值为0或者1的格子);
当到达 (N-1, N-1) 后,你要继续走,直到返回到 (0, 0) ,只能向上或向左走,并且只能穿越有效的格子;
当你经过一个格子且这个格子包含一个樱桃时,你将摘到樱桃并且这个格子会变成空的(值变为0);
如果在 (0, 0) 和 (N-1, N-1) 之间不存在一条可经过的路径,则没有任何一个樱桃能被摘到。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cherry-pickup
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

记忆化搜索

import java.util.HashMap;
import java.util.Map;

class Solution {

    private Info[][][] cache;

    private final int[] dx = {0, 1};

    private final int[] dy = {1, 0};

    private int[][] grid;

    private int n;

    private int m;

    private Info solve(int x1, int y1, int x2, int y2) {
        if (cache[x1][y1][x2] != null) {
            return cache[x1][y1][x2];
        }

        if (x1 == n - 1 && y1 == m - 1) {
            Info info = new Info(true, grid[x1][y1]);
            cache[x1][y1][x2] = info;
            return info;
        }

        if (grid[x1][y1] == -1) {
            Info info = new Info(false, 0);
            cache[x1][y1][x2] = info;
            return info;
        }

        if (grid[x2][y2] == -1) {
            Info info = new Info(false, 0);
            cache[x1][y1][x2] = info;
            return info;
        }

        boolean ok = false;
        int value = 0;

        Info best = new Info(false, 0);

        for (int i = 0; i < 2; ++i) {

            for (int j = 0; j < 2; ++j) {
                int nx1 = x1 + dx[i];
                int ny1 = y1 + dy[i];
                int nx2 = x2 + dx[j];
                int ny2 = y2 + dy[j];

                if (nx1 >= 0 && nx1 < n && ny1 >= 0 && ny1 < m && nx2 >= 0 && nx2 < n && ny2 >= 0 && ny2 < m) {
                    Info next = solve(nx1, ny1, nx2, ny2);
                    if (next.ok && (!best.ok || next.value > best.value)) {
                        best.ok = next.ok;
                        best.value = next.value;
                    }
                }
            }
        }

        if (best.ok) {
            best.value += grid[x1][y1];
            if (x1 != x2) {
                best.value += grid[x2][y2];
            }
        }

        cache[x1][y1][x2] = best;

        return best;
    }

    public int cherryPickup(int[][] grid) {
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }
        this.cache = new Info[grid.length][grid[0].length][grid.length];
        this.grid = grid;
        this.n = grid.length;
        this.m = grid[0].length;

        Info info = solve(0, 0, 0, 0);
        return info.ok ? info.value : 0;
    }
}

class Info {
    boolean ok;
    int value;

    public Info(boolean ok, int value) {
        this.ok = ok;
        this.value = value;
    }
}

动态规划

import java.util.Arrays;

class Solution {
    public int cherryPickup(int[][] grid) {
        int n = grid.length;
        int m = grid[0].length;
        int[][] dp = new int[n][m];

        for (int i = 0; i < n; ++i) {
            Arrays.fill(dp[i], -1);
        }

        dp[0][0] = grid[0][0];

        for (int t = 1; t <= 2 * n - 2; t++) {
            int[][] tmp = new int[n][m];

            for (int i = 0; i < n; ++i) {
                Arrays.fill(tmp[i], -1);
            }
            
            for (int i = Math.max(0, t - (n - 1)); i <= Math.min(n - 1, t); i++) {

                for (int j = Math.max(0, t - (n - 1)); j <= Math.min(n - 1, t); j++) {

                    if (grid[i][t - i] == -1 || grid[j][t - j] == -1) {
                        continue;
                    }

                    int res = grid[i][t - i];
                    if (i != j) {
                        // 不重合的时候加上另一个坐标
                        res += grid[j][t - j];
                    }

                    for (int pi = i - 1; pi <= i; pi++) {
                        for (int pj = j - 1; pj <= j; pj++) {
                            if (pi >= 0 && pj >= 0 && dp[pi][pj] != -1) {
                                tmp[i][j] = Math.max(tmp[i][j], dp[pi][pj] + res);
                            }
                        }
                    }
                }
            }
            dp = tmp;
        }
        return Math.max(0, dp[n - 1][n - 1]);
    }
}
posted @ 2021-12-20 21:33  Tianyiya  阅读(39)  评论(0)    收藏  举报