2026-03-29:网格中得分最大的路径。用go语言,给定一个大小为 m x n 的网格 grid,每个格子里的值只可能是 0、1、2,再给定一个整数 k。

0 阅读7分钟

2026-03-29:网格中得分最大的路径。用go语言,给定一个大小为 m x n 的网格 grid,每个格子里的值只可能是 0、1、2,再给定一个整数 k。

从左上角 (0,0) 出发,要走到右下角 (m-1,n-1)。移动规则只有两种:向右或向下。每条路径由一串按顺序经过的格子组成。

路径过程中,每经过一个格子,会产生“分数”和“花费”的变化,规则如下:

  • 格子值为 0:分数 +0,花费 +0

  • 格子值为 1:分数 +1,花费 +1

  • 格子值为 2:分数 +2,花费 +1

要求:所有经过的格子累加后的总花费不能超过 k。如果走不到终点,或者任意到达终点的路径总花费都超过 k,则认为不存在有效路径。

输出:在花费 ≤ k 的前提下,能得到的最大总分数;若不存在有效路径则返回 -1。

1 <= m, n <= 200。

0 <= k <= 1000。

​​​​​​​grid[0][0] == 0。

0 <= grid[i][j] <= 2。

输入: grid = [[0, 1],[2, 0]], k = 1。

输出: 2。

解释:

最佳路径为:

单元格grid[i][j]当前分数累计分数当前花费累计花费
(0, 0)00000
(1, 0)22211
(1, 1)00201

因此,可获得的最大分数为 2。

题目来自萝莉控3742。

一、先明确核心规则(必看)

  1. 移动限制:只能向右向下走,从左上角(0,0)到右下角(1,1)
  2. 分数/花费规则
    • 格子=0:分数+0,花费+0
    • 格子=1:分数+1,花费+1
    • 格子=2:分数+2,花费+1
  3. 约束:总花费 ≤ 给定k,求最大分数;无有效路径返回-1
  4. 路径长度:从(0,0)到(1,1),固定走3个格子(2步),所有路径花费最多为2

二、第一步:计算「最小花费」(判断是否存在有效路径)

代码中第一个函数minPathSum的作用:计算从起点到终点的最小可能总花费。 因为只有当「最小花费 ≤ k」时,才存在有效路径;否则直接返回-1。

执行过程:

  1. 遍历网格每一行、每一个格子,按照规则累加最小花费
  2. 格子0不花钱,格子1/2都花1,计算所有路径中花钱最少的那条
  3. 样例计算结果:最小花费=1
  4. 对比k=1:1 ≤ 1 → 存在有效路径,继续计算最大分数

三、第二步:动态规划初始化(准备计算最大分数)

这一步是为了搭建计算框架,记录到达每个位置、花费不同步数时的最大分数。 核心概念:dp[列][总花费] = 最大分数

初始化细节:

  1. 网格大小:2行2列,k=1
  2. 优化:路径最大花费不超过行数+列数-2(样例=2),所以k上限取1
  3. 创建二维记录数组:列数+1 × (k+2),所有值初始化为「负无穷」(代表不可达)
  4. 起点赋值:(0,0)格子是0,分数0、花费0 → 初始状态:到达第1列、花费1时,分数为0

四、第三步:逐行逐格遍历计算(核心步骤)

按照从上到下、从左到右的顺序,遍历网格中每一个格子,更新每个位置的最大分数。 遍历顺序:(0,0) → (0,1) → (1,0) → (1,1)

子步骤1:处理格子 (0,0) (值=0)

  • 分数+0,花费+0
  • 无新计算,保持初始状态:分数0,花费0

子步骤2:处理格子 (0,1) (值=1)

  • 只能从左边(0,0)向右走过来
  • 规则:分数+1,花费+1
  • 累计状态:分数=1,总花费=1
  • 记录:到达该位置、花费1时,最大分数=1

子步骤3:处理格子 (1,0) (值=2)

  • 只能从上面(0,0)向下走过来
  • 规则:分数+2,花费+1
  • 累计状态:分数=2,总花费=1
  • 记录:到达该位置、花费1时,最大分数=2

子步骤4:处理终点格子 (1,1) (值=0)

这是最终目的地,有两条路径可以到达:

  1. 路径1:从上方(0,1)下来
    • 原分数1,原花费1;格子0不加分、不花钱
    • 最终:分数1,花费1
  2. 路径2:从左侧(1,0)过来
    • 原分数2,原花费1;格子0不加分、不花钱
    • 最终:分数2,花费1
  • 取最大值:终点最大分数=2
  • 总花费=1 ≤ k=1,符合要求

五、第四步:提取最终结果

遍历终点位置所有「花费≤k」的分数值,找到最大值:2 直接输出结果2。


时间复杂度 & 额外空间复杂度 分析

1. 时间复杂度

定义:

  • 网格行数:m,列数:n
  • 最大允许花费:K

计算过程:

  1. 最小花费计算:遍历所有格子 → O(m×n)O(m×n)
  2. 最大分数计算:双重遍历格子 + 每层遍历花费K → O(m×n×K)O(m×n×K)

总时间复杂度:O(m×n×K)O(m×n×K) (m和n最大200,K最大1000,总运算量在合理范围内)

2. 额外空间复杂度

额外空间:除了输入网格外,代码主动开辟的内存空间

  1. 最小花费计算:开辟1个一维数组 → O(n)O(n)
  2. 最大分数计算:开辟1个二维数组 (n+1) × (K+2)O(n×K)O(n×K)

总额外空间复杂度:O(n×K)O(n×K)


总结

  1. 解题分4步:算最小花费→初始化→逐格动态规划→取最大值
  2. 样例最优路径:(0,0)→(1,0)→(1,1),总分2,总花费1
  3. 时间复杂度:O(m×n×K)O(m×n×K)
  4. 额外空间复杂度:O(n×K)O(n×K)

Go完整代码如下:

package main

import (
	"fmt"
	"math"
	"slices"
)

// 64. 最小路径和
func minPathSum(grid [][]int) int {
	n := len(grid[0])
	f := make([]int, n+1)
	for j := range f {
		f[j] = math.MaxInt
	}
	f[1] = 0
	for _, row := range grid {
		for j, x := range row {
			f[j+1] = min(f[j], f[j+1]) + min(x, 1) // 值大于 0 的单元格花费 1
		}
	}
	return f[n]
}

func maxPathScore(grid [][]int, K int) int {
	if minPathSum(grid) > K {
		return -1
	}

	m, n := len(grid), len(grid[0])
	K = min(K, m+n-2) // 至多花费 m+n-2
	f := make([][]int, n+1)
	for j := range f {
		f[j] = make([]int, K+2)
		for k := range f[j] {
			f[j][k] = math.MinInt
		}
	}
	f[1][1] = 0

	for i, row := range grid {
		for j, x := range row {
			for k := min(K, i+j); k >= 0; k-- { // 从 (0,0) 到 (i,j) 至多花费 i+j
				newK := k
				if x > 0 {
					newK--
				}
				f[j+1][k+1] = max(f[j+1][newK+1], f[j][newK+1]) + x
			}
		}
	}

	return slices.Max(f[n])
}

func main() {
	grid := [][]int{{0, 1}, {2, 0}}
	k := 1
	result := maxPathScore(grid, k)
	fmt.Println(result)
}

在这里插入图片描述

Python完整代码如下:

# -*-coding:utf-8-*-

import math

def minPathSum(grid):
    """
    64. 最小路径和
    计算从左上角到右下角的最小路径和(值大于0的单元格花费1)
    """
    n = len(grid[0])
    f = [math.inf] * (n + 1)
    f[1] = 0
    
    for row in grid:
        for j, x in enumerate(row):
            f[j + 1] = min(f[j], f[j + 1]) + min(x, 1)
    
    return int(f[n])

def maxPathScore(grid, K):
    """
    计算最大路径分数
    """
    if minPathSum(grid) > K:
        return -1
    
    m, n = len(grid), len(grid[0])
    K = min(K, m + n - 2)  # 至多花费 m+n-2
    
    # 初始化DP表:f[j][k] 表示到达第j列时花费k的最大分数
    f = [[-math.inf] * (K + 2) for _ in range(n + 1)]
    f[1][1] = 0
    
    for i, row in enumerate(grid):
        for j, x in enumerate(row):
            # 从 (0,0) 到 (i,j) 至多花费 i+j
            max_k = min(K, i + j)
            for k in range(max_k, -1, -1):
                newK = k
                if x > 0:
                    newK -= 1
                if newK >= 0:
                    f[j + 1][k + 1] = max(
                        f[j + 1][newK + 1],
                        f[j][newK + 1]
                    ) + x
                else:
                    f[j + 1][k + 1] = -math.inf
    
    return int(max(f[n]))

def main():
    grid = [[0, 1], [2, 0]]
    k = 1
    result = maxPathScore(grid, k)
    print(result)

if __name__ == "__main__":
    main()

在这里插入图片描述

C++完整代码如下:

#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>

using namespace std;

// 64. 最小路径和
int minPathSum(vector<vector<int>>& grid) {
    int n = grid[0].size();
    vector<int> f(n + 1, INT_MAX);
    f[1] = 0;

    for (auto& row : grid) {
        for (int j = 0; j < n; j++) {
            int x = row[j];
            f[j + 1] = min(f[j], f[j + 1]) + min(x, 1); // 值大于 0 的单元格花费 1
        }
    }

    return f[n];
}

int maxPathScore(vector<vector<int>>& grid, int K) {
    if (minPathSum(grid) > K) {
        return -1;
    }

    int m = grid.size();
    int n = grid[0].size();
    K = min(K, m + n - 2); // 至多花费 m+n-2

    // 初始化DP表:f[j][k] 表示到达第j列时花费k的最大分数
    vector<vector<int>> f(n + 1, vector<int>(K + 2, INT_MIN));
    f[1][1] = 0;

    for (int i = 0; i < m; i++) {
        auto& row = grid[i];
        for (int j = 0; j < n; j++) {
            int x = row[j];
            // 从 (0,0) 到 (i,j) 至多花费 i+j
            int max_k = min(K, i + j);
            for (int k = max_k; k >= 0; k--) {
                int newK = k;
                if (x > 0) {
                    newK--;
                }
                if (newK >= 0) {
                    f[j + 1][k + 1] = max(f[j + 1][newK + 1], f[j][newK + 1]) + x;
                } else {
                    f[j + 1][k + 1] = INT_MIN;
                }
            }
        }
    }

    return *max_element(f[n].begin(), f[n].end());
}

int main() {
    vector<vector<int>> grid = {{0, 1}, {2, 0}};
    int k = 1;
    int result = maxPathScore(grid, k);
    cout << result << endl;

    return 0;
}

在这里插入图片描述