AcWing1027.方格取数
题目链接:AcWing1027.方格取数
1. 题目描述
设有
N
×
N
N \times N
N×N 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字
0
0
0 。如下图所示:
某人从图中的左上角
A
A
A 出发,可以向下行走,也可以向右行走,直到到达右下角的
B
B
B 点。
在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字 0 0 0)。
此人从 A A A 点到 B B B 点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。
输入格式
第一行为一个整数
N
N
N ,表示
N
×
N
N \times N
N×N 的方格图。
接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。
行和列编号从
1
1
1 开始。
一行“0 0 0”表示结束。
输出格式
输出一个整数,表示两条路径上取得的最大的和。
数据范围
N
≤
10
N \leq 10
N≤10
输入样例:
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
2. 解题思路
通读整道题,显而易见可以设状态为
f
(
i
1
,
j
1
,
i
2
,
j
2
)
f(i_1, j_1, i_2, j_2)
f(i1,j1,i2,j2) ,代表从
(
1
,
1
)
(1, 1)
(1,1) 出发走两次分别走到
(
i
1
,
j
1
)
(i_1, j_1)
(i1,j1) 和
(
i
2
,
j
2
)
(i_2, j_2)
(i2,j2) 所取得路径和。
但这种状态表示处理“同一个格子不能被重复取值”有些复杂。
那么同一个格子重复的条件是:
i
1
+
j
1
=
=
i
2
+
j
2
i_1 + j_1 == i_2 + j_2
i1+j1==i2+j2。
据此条件,我们可以简化状态定义。可以定义为:
f
(
k
,
i
1
,
i
2
)
f(k, i_1, i_2)
f(k,i1,i2) ,代表所有从
(
1
,
1
)
(1, 1)
(1,1) 走到
(
i
1
,
k
−
i
1
)
(i_1, k - i_1)
(i1,k−i1) 和
(
i
2
,
k
−
i
2
)
(i_2, k - i_2)
(i2,k−i2) 的路径的最大值。
k
k
k 表示两条路线走到的格子的横纵坐标之和。
动态规划分析:
状态表示
f
(
k
,
i
1
,
i
2
)
f(k, i_1, i_2)
f(k,i1,i2) :所有从
(
1
,
1
)
(1, 1)
(1,1) 走到
(
i
1
,
k
−
i
1
)
(i_1, k - i_1)
(i1,k−i1) 和
(
i
2
,
k
−
i
2
)
(i_2, k - i_2)
(i2,k−i2) 的走法。
属性:
m
a
x
max
max (走法的最大值)。
状态计算:
t
=
w
(
i
1
,
j
1
)
+
{
w
(
i
2
,
j
2
)
?
}
t = w(i_1, j_1) + \{w(i_2, j_2)?\}
t=w(i1,j1)+{w(i2,j2)?} (若
i
1
=
=
i
2
i_1 == i_2
i1==i2 则不加第二部分,否则加第二部分)
- 1:向下、2:向下 : m a x { f ( k , i 1 , i 2 ) , f ( k − 1 , i 1 − 1 , i 2 − 1 ) + t } max\{f(k, i_1, i_2), f(k - 1, i_1 - 1, i_2 - 1) + t\} max{f(k,i1,i2),f(k−1,i1−1,i2−1)+t}
- 1:向下、2:向右 : m a x { f ( k , i 1 , i 2 ) , f ( k − 1 , i 1 − 1 , i 2 ) + t } max\{f(k, i_1, i_2), f(k - 1, i_1 - 1, i_2) + t\} max{f(k,i1,i2),f(k−1,i1−1,i2)+t}
- 1:向右、2:向下 : m a x { f ( k , i 1 , i 2 ) , f ( k − 1 , i 1 , i 2 − 1 ) + t } max\{f(k, i_1, i_2), f(k - 1, i_1, i_2 - 1) + t\} max{f(k,i1,i2),f(k−1,i1,i2−1)+t}
- 1:向右、2:向右 : m a x { f ( k , i 1 , i 2 ) , f ( k − 1 , i 1 , i 2 ) + t } max\{f(k, i_1, i_2), f(k - 1, i_1, i_2) + t\} max{f(k,i1,i2),f(k−1,i1,i2)+t}
3. 代码实现
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 15;
int n;
int w[N][N];
int f[N * 2][N][N];
int main()
{
cin >> n;
int a, b, c;
while(cin >> a >> b >> c, a || b || c) w[a][b] = c;
for (int k = 2; k <= 2 * n; k ++ )
for (int i1 = 1; i1 <= n; i1 ++ )
for (int i2 = 1; i2 <= n; i2 ++ )
{
int j1 = k - i1, j2 = k - i2;
int t = w[i1][j1];
if (i1 != i2) t += w[i2][j2];
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][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] + t);
}
printf("%d\n", f[n * 2][n][n]);
return 0;
}
4. 时间复杂度分析
三重循环,第一重循环 2 n 2n 2n 次,第二重循环 n n n 次,第三重循环 n n n 次,所以整体的时间复杂度是: O ( n 3 ) O(n^3) O(n3)
5. 说明
- 上面分析中说的同一格子重复的条件是步数相同,当步数不相同时,由于不能走回头路,所以终点一定不同。