最大得分的路径数目

最大得分的路径数目

给你一个正方形字符数组 board ,你从数组最右下方的字符 'S' 出发。

你的目标是到达数组最左上角的字符 'E' ,数组剩余的部分为数字字符 1, 2, ..., 9 或者障碍 'X'。在每一步移动中,你可以向上、向左或者左上方移动,可以移动的前提是到达的格子没有障碍。

一条路径的 「得分」 定义为:路径上所有数字的和。

请你返回一个列表,包含两个整数:第一个整数是 「得分」 的最大值,第二个整数是得到最大得分的方案数,请把结果对 10^9 + 7 取余

如果没有任何路径可以到达终点,请返回 [0, 0]

示例 1:

输入:board = ["E23","2X2","12S"]
输出:[7,1]

示例 2:

输入:board = ["E12","1X1","21S"]
输出:[4,2]

示例 3:

输入:board = ["E11","XXX","11S"]
输出:[0,0]

提示:

  • 2 <= board.length == board[i].length <= 100

代码:

状态转移方程为:
f [ ( x , y ) ] = m a x ( f [ ( x + 1 , y ) ] , f [ ( x , y + 1 ) ] , f [ ( x + 1 , y + 1 ) ] ) + b o a r d [ ( x , y ) ] f[(x,y)]=max(f[(x+1,y)],f[(x,y+1)],f[(x+1,y+1)])+board[(x,y)] f[(x,y)]=max(f[(x+1,y)],f[(x,y+1)],f[(x+1,y+1)])+board[(x,y)]

/*
动态规划

定义
	dp[i][j] 表示从起点到位置i,j的状态,包含刘昂部分,即 得分 和 路径数量 两部分

初始化
    dp[n-1][n-1] = {0, 1}
    其他均初始化为 {-1, 0}

计算
    从右下角开始计算,即从大到小
    考虑三种情况到x,y

    x+1, y
    x, y+1
    x+1, y+1
结果
	dp[0][0]的结果,记得要考虑是否可达的情况


*/

class Solution {
private:
    int n;
    int base = 1000000007;
    // 合并的结果函数:需要考虑两种情况(1、找到更大的值,即直接更新结果;2、找到一样的值,则方案数量要累加)
    // x,y表示目的地, sx,sy表示起始点
    void reach(vector<vector<vector<int>>>& dp, int x, int y, int sx, int sy)
    {
        if (sx < n && sy < n && dp[sx][sy][0] >= 0)
        {
            if (dp[sx][sy][0] > dp[x][y][0])
            {
                dp[x][y] = dp[sx][sy];
            }
            else if (dp[sx][sy][0] == dp[x][y][0])
            {
                dp[x][y][1] += dp[sx][sy][1];
                dp[x][y][1] %= base;
            }
        }
    }

public:
    vector<int> pathsWithMaxScore(vector<string>& board) {
        n = board.size();

        vector<vector<vector<int>>> dp(n, vector<vector<int>>(n, {-1, 0}));
        dp[n-1][n-1] = {0, 1};
        // 设置board为'0'减少后续判断
        board[0][0] = '0';
        for (int i = n-1; i >= 0; --i)
        {
            for (int j = n-1; j >= 0; --j)
            {
                if (i == n-1 && j == n-1)
                {
                    continue;
                }
                else if (board[i][j] == 'X')
                {
                    continue;
                }

                reach(dp, i, j, i+1, j);
                reach(dp, i, j, i, j+1);
                reach(dp, i, j, i+1, j+1);
                if (dp[i][j][0] != -1)
                {
                    dp[i][j][0] += board[i][j] - '0';
                }
            }
        }

        return dp[0][0][0] == -1 ? vector<int>(2,0) : dp[0][0];
    }
};
//优化版

using PII = pair<int, int>;

class Solution {
private:
    static constexpr int mod = (int)1e9 + 7;

public:
    void update(vector<vector<PII>>& dp, int n, int x, int y, int u, int v) {
        if (u >= n || v >= n || dp[u][v].first == -1) {
            return;
        }
        if (dp[u][v].first > dp[x][y].first) {
            dp[x][y] = dp[u][v];
        }
        else if (dp[u][v].first == dp[x][y].first) {
            dp[x][y].second += dp[u][v].second;
            if (dp[x][y].second >= mod) {
                dp[x][y].second -= mod;
            }
        }
    }

    vector<int> pathsWithMaxScore(vector<string>& board) {
        int n = board.size();
        vector<vector<PII>> dp(n, vector<PII>(n, {-1, 0}));
        dp[n - 1][n - 1] = {0, 1};
        for (int i = n - 1; i >= 0; --i) {
            for (int j = n - 1; j >= 0; --j) {
                if (!(i == n - 1 && j == n - 1) && board[i][j] != 'X') {
                    update(dp, n, i, j, i + 1, j);
                    update(dp, n, i, j, i, j + 1);
                    update(dp, n, i, j, i + 1, j + 1);
                    if (dp[i][j].first != -1) {
                        dp[i][j].first += (board[i][j] == 'E' ? 0 : board[i][j] - '0');
                    }
                }
            }
        }
        return dp[0][0].first == -1 ? vector<int>{0, 0} : vector<int>{dp[0][0].first, dp[0][0].second};
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值