【题目描述】
设有N×N的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。如下图所示:
某人从图中的左上角A出发,可以向下行走,也可以向右行走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从A点到B点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。
【输入】
第一行为一个整数N(N≤10),表示N×N的方格图。
接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。一行“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
【输出样例】
67
分析
- 题意就是两个人同时从起点走,然后取到达终点的最大值**;两个人同时走**(不走回头路),在任何时刻,他们的横纵坐标和一定相等(即i1+j1 == i2+j2);所以当i1==i2的时候,这两个人一定位于同一个格子;
- 所以可以用状态转移方程f[i1][j1][i2][j2]来表示这两个人分别走到(i1,j1)、(i2,j2)时的最大数字和,但是由于同一时刻两人走的步数一样,所以可以用k = i1+j1 = i2+j2,所以状态转移方程降到三维,f[k][i1][i2]:k为横纵坐标和,i1为第一个人的横坐标,i2为第二个人的横坐标,f[k][i1][i2]的值就是走到(i1,j1)、(i2,j2)当前最大和;
- 直接分析最后一个状态的情况,两个坐标两两组合,一共有如下图四种情况;f(k-1,i1-1,i2-1)、f(k-1,i1-1,i2)、f(k-1,i1,i2-1)、f(k-1,i1,i2);
#include<bits/stdc++.h>
using namespace std;
const int N = 15;
int n;
int arr[N][N];
int f[N * 2][N][N];// f[k][i1][i2]:k为横纵坐标和,i1为第一个人的横坐标,i2为第二个人的横坐标
int main() {
cin >> n;
int a, b, c;
while (cin >> a >> b >> c, a || b || c) {
arr[a][b] = c;
}
for (int k = 2; k <= n + n; ++k) {
for (int i1 = 1; i1 <= n; ++i1) {
for (int i2 = 1; i2 <= n; ++i2) {
// k = i1+j1 = i2+j2
int j1 = k - i1, j2 = k - i2;
if (j1 >= 1 && j2 >= 1 && j1 <= n && j2 <= n) {
int t;//当前两个人分别走到(i1,j1)、(i2,j2)这两个点的数字值
//两人当前在同一个格子,只用算一个格子
if (i1 == i2) {
//i1==i2,j1=k-i1=j2=k-i2
t = arr[i1][k - i1];
} else {
//两人不在同一格子,是两个格子的和
t = arr[i1][k - i1] + arr[i2][k - i2];
}
//两个人都是往下过来的
f[k][i1][i2] = max(f[k][i1][i2], f[k - 1][i1 - 1][i2 - 1] + t);
//一下一右
f[k][i1][i2] = max(f[k][i1][i2], f[k - 1][i1 - 1][i2] + t);
//一右一下
f[k][i1][i2] = max(f[k][i1][i2], f[k - 1][i1][i2 - 1] + t);
//一右一右
f[k][i1][i2] = max(f[k][i1][i2], f[k - 1][i1][i2] + t);
}
}
}
}
cout << f[2 * n][n][n];
return 0;
}