每日一练 洛谷 方格取数
我们面对的是一个经典的动态规划问题,题目要求在给定的 N×N 方格图中找到两条从左上角 A 点到右下角 B 点的路径,使得路径上取得的数之和最大。每个方格中的数字只能取一次,并且每次移动只能向右或向下。输入输出格式输入:首先是一个整数 N(表示 N×N 的方格图),接下来的每行有三个整数,前两个表示位置(x, y),第三个数为该位置上所放的数。一行单独的0 0 0表示输入结束。输出:只需输出一个整
题目描述
设有 N×N 的方格图 (N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 0。如下图所示(见样例):

某人从图的左上角的 A 点出发,可以向下行走,也可以向右走,直到到达右下角的 B 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 0)。
此人从 A 点到 B 点共走两次,试找出 2 条这样的路径,使得取得的数之和为最大。
输入格式
输入的第一行为一个整数 N(表示 N×N 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 0 表示输入结束。
输出格式
只需输出一个整数,表示 2 条路径上取得的最大的和。
输入输出样例
输入
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
输出
67
说明/提示
数据范围:1≤N≤9。
题目解析与解法介绍
我们面对的是一个经典的动态规划问题,题目要求在给定的 N×N 方格图中找到两条从左上角 A 点到右下角 B 点的路径,使得路径上取得的数之和最大。每个方格中的数字只能取一次,并且每次移动只能向右或向下。
输入输出格式
- 输入:首先是一个整数 N(表示 N×N 的方格图),接下来的每行有三个整数,前两个表示位置(x, y),第三个数为该位置上所放的数。一行单独的
0 0 0表示输入结束。 - 输出:只需输出一个整数,表示两条路径上取得的最大和。
样例分析
对于给定的样例:
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
我们需要构造出一个 8×8 的矩阵,并将给定的数值填入对应的位置。其余未提及的位置默认值为 0。
解题思路
为了求解这个问题,我们可以使用动态规划的方法。由于需要同时考虑两条路径,因此状态空间会稍微复杂一些。具体步骤如下:
- 初始化矩阵:根据输入数据初始化一个 N×N 的矩阵,未指定的位置设为 0。
- 定义状态:设
dp[i][j][k][l]表示第一条路径走到(i,j),第二条路径走到(k,l)时的最大和。 - 状态转移方程:
- 如果两条路径不重合,则当前最大和为
dp[i-1][j][k-1][l],dp[i-1][j][k][l-1],dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]中的最大值加上当前位置的值。 - 如果两条路径重合,则当前最大和为
dp[i-1][j][k-1][l],dp[i-1][j][k][l-1],dp[i][j-1][k-1][l],dp[i][j-1][k][l-1]中的最大值加上当前位置的值(只加一次)。
- 如果两条路径不重合,则当前最大和为
- 边界条件:初始状态为
dp[0][0][0][0] = grid[0][0]。 - 最终结果:
dp[N-1][N-1][N-1][N-1]即为所求的最大和。
代码实现
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int MAX_N = 9;
int grid[MAX_N][MAX_N];
int dp[MAX_N+1][MAX_N+1][MAX_N+1][MAX_N+1];
void initializeGrid(int N) {
memset(grid, 0, sizeof(grid));
memset(dp, 0, sizeof(dp));
int x, y, value;
while (true) {
cin >> x >> y >> value;
if (x == 0 && y == 0 && value == 0) break;
grid[x-1][y-1] = value; // 转换为0-based索引
}
}
int maxPathSum(int N) {
dp[0][0][0][0] = grid[0][0];
for (int i = 0; i <= N; ++i) {
for (int j = 0; j <= N; ++j) {
for (int k = 0; k <= N; ++k) {
for (int l = 0; l <= N; ++l) {
if (i == 0 && j == 0 && k == 0 && l == 0) continue;
int prev_max = 0;
if (i > 0 && k > 0) prev_max = max(prev_max, dp[i-1][j][k-1][l]);
if (i > 0 && l > 0) prev_max = max(prev_max, dp[i-1][j][k][l-1]);
if (j > 0 && k > 0) prev_max = max(prev_max, dp[i][j-1][k-1][l]);
if (j > 0 && l > 0) prev_max = max(prev_max, dp[i][j-1][k][l-1]);
if (i != k || j != l) { // 不重合
dp[i][j][k][l] = prev_max + grid[i-1][j-1] + grid[k-1][l-1];
} else { // 重合
dp[i][j][k][l] = prev_max + grid[i-1][j-1];
}
}
}
}
}
return dp[N][N][N][N];
}
int main() {
int N;
cin >> N;
initializeGrid(N);
cout << maxPathSum(N) << endl;
return 0;
}
解题过程
-
初始化矩阵:
- 使用
memset初始化grid和dp数组。 - 读取输入数据并填充
grid,注意将输入的坐标转换为 0-based 索引。
- 使用
-
动态规划核心逻辑:
- 定义
dp[i][j][k][l]为两条路径分别到达(i,j)和(k,l)时的最大和。 - 通过四个循环遍历所有可能的状态组合。
- 对于每个状态,计算其前驱状态的最大值,并加上当前位置的值。如果两条路径重合,则只加一次。
- 定义
-
输出结果:
- 最终的结果存储在
dp[N][N][N][N]中,即两条路径都到达终点(N-1, N-1)的最大和。
- 最终的结果存储在
时间复杂度分析
- 由于四维数组的大小为
O(N^4),每个状态的更新需要常数时间,因此总的时间复杂度为O(N^4)。对于 N ≤ 9 的情况,这个复杂度是可以接受的。
更多推荐



所有评论(0)