Skip to content
本博客自 2023 年 4 月 4 日起转为归档状态,可能不再发表新的博文。点此了解博主的竞赛生涯
This blog has been archived by the owner since April 4, 2023. It may no longer have new updates.

洛谷 - P1004 方格取数

检测到 KaTeX 加载失败,可能会导致文中的数学公式无法正常渲染。

#题面

#题目描述

设有 N×NN \times N 的方格图 (N9)(N \le 9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 00。如下图所示(见样例):

A
 0  0  0  0  0  0  0  0
 0  0 13  0  0  6  0  0
 0  0  0  0  7  0  0  0
 0  0  0 14  0  0  0  0
 0 21  0  0  0  4  0  0
 0  0 15  0  0  0  0  0
 0 14  0  0  0  0  0  0
 0  0  0  0  0  0  0  0
                        B

某人从图的左上角的 AA 点出发,可以向下行走,也可以向右走,直到到达右下角的 BB 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 00)。 此人从 AA 点到 BB 点共走两次,试找出 22 条这样的路径,使得取得的数之和为最大。

#输入格式

输入的第一行为一个整数 NN(表示 N×NN \times N 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 00 表示输入结束。

#输出格式

只需输出一个整数,表示 22 条路径上取得的最大的和。

#输入输出样例

样例输入 #1

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

样例输出 #1

67

#思路

本题是一道四维动态规划模板题。

使用数组的第一维、第二维记录第一次走的路径,第三维、第四维记录第二次走的路径,容易推出转移方程:

fi,j,k,l=max{fi1,j,k1,l, fi1,j,k,l1, fi,j1,k1,l, fi,j1,k,l1}+wi,j+wk,lf_{i, j, k, l} = \max\{f_{i-1, j, k-1, l},~f_{i-1, j, k, l-1},~f_{i, j-1, k-1, l},~f_{i, j-1, k, l-1}\} + w_{i, j} + w_{k, l}

i=ki = kj=lj = l 时,需要减去重复的数字: fi,j,k,l=fi,j,k,lwi,jf_{i, j, k, l} = f_{i, j, k, l} - w_{i, j}

最后 fn,n,n,nf_{n, n, n, n} 即为所求。

#代码

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <bits/stdc++.h>

using namespace std;

int n, r, c, k, w[15][15], f[15][15][15][15];

int main() {
cin >> n;
while (cin >> r >> c >> k, r && c && k) {
w[r][c] = k;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
for (int k = 1; k <= n; k++) {
for (int l = 1; l <= n; l++) {
f[i][j][k][l] = max({f[i - 1][j][k - 1][l], f[i - 1][j][k][l - 1], f[i][j - 1][k - 1][l], f[i][j - 1][k][l - 1]}) + w[i][j] + w[k][l];
if (i == k && j == l) f[i][j][k][l] -= w[i][j];
}
}
}
}
cout << f[n][n][n][n] << endl;
return 0;
}