题目描述
设有 N × N N \times N N×N 的方格图 ( N ≤ 9 ) (N \le 9) (N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 0 0 0。如下图所示(见样例):
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
某人从图的左上角的
A
A
A 点出发,可以向下行走,也可以向右走,直到到达右下角的
B
B
B 点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字
0
0
0)。
此人从
A
A
A 点到
B
B
B 点共走两次,试找出
2
2
2 条这样的路径,使得取得的数之和为最大。
输入格式
输入的第一行为一个整数 N N N(表示 N × N N \times N N×N 的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的 0 0 0 表示输入结束。
输出格式
只需输出一个整数,表示 2 2 2 条路径上取得的最大的和。
样例 #1
样例输入 #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
算法思想(暴力出奇迹+80分)
根据题目要求:
此人从 A A A 点到 B B B 点共走两次,试找出 2 2 2 条这样的路径,使得取得的数之和为最大。
可以使用DFS同时搜索这两条路径,分别记录走到每一个位置 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)时取得的数字之和 s 1 s_1 s1、 s 2 s_2 s2。当走到终点时,打擂台求出最大值。
注意,当两条路径走到同一位置时,只能取一次数。
代码实现
#include <iostream>
using namespace std;
const int N = 15;
int w[N][N];
int n, ans;
void dfs(int x1, int y1, int s1, int x2, int y2, int s2)
{
//越界
if(x1 > n || y1 > n || x2 > n || y2 > n) return;
//到达终点
if(x1 == n && y1 == n && x2 == n && y2 == n)
{
ans = max(ans, s1 + s2 + w[n][n]); //加上终点上的数
return;
}
//走到相同位置,只取一次数
if(x1 == x2 && y1 == y2)
{
dfs(x1 + 1, y1, s1 + w[x1][y1], x2 + 1, y2, s2); //路径1向下走,路径2向下走
dfs(x1 + 1, y1, s1 + w[x1][y1], x2, y2 + 1, s2); //路径1向下走,路径2向右走
dfs(x1, y1 + 1, s1 + w[x1][y1], x2 + 1, y2, s2); //路径1向右走,路径2向下走
dfs(x1, y1 + 1, s1 + w[x1][y1], x2, y2 + 1, s2); //路径1向右走,路径2向右走
}
else
{
dfs(x1 + 1, y1, s1 + w[x1][y1], x2 + 1, y2, s2 + w[x2][y2]);
dfs(x1 + 1, y1, s1 + w[x1][y1], x2, y2 + 1, s2 + w[x2][y2]);
dfs(x1, y1 + 1, s1 + w[x1][y1], x2 + 1, y2, s2 + w[x2][y2]);
dfs(x1, y1 + 1, s1 + w[x1][y1], x2, y2 + 1, s2 + w[x2][y2]);
}
}
int main()
{
int x, y, z;
cin >> n;
while(cin >> x >> y >> z, x || y || z) w[x][y] = z;
dfs(1, 1, 0, 1, 1, 0);
cout << ans << endl;
return 0;
}
算法思想(动态规划+100分)
状态表示
通过上面的暴力搜索发现其实要求的就是两条路径到达 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2)时得的数字之和的最大值,因此可以用状态 f ( x 1 , y 1 , x 2 , y 2 ) f(x_1,y_1,x_2,y_2) f(x1,y1,x2,y2)表示。
状态计算
计算状态 f ( x 1 , y 1 , x 2 , y 2 ) f(x_1,y_1,x_2,y_2) f(x1,y1,x2,y2)的值可以分为两类:
- 走到相同位置,即
x
1
=
x
2
、
y
1
=
y
2
x_1=x_2、y_1=y_2
x1=x2、y1=y2,那么在该位置上只取一次数。此时应该取下面
4
4
4种情况的最大值,再加上
w
(
x
1
,
y
1
)
w(x_1,y_1)
w(x1,y1)。
- 路径1从上面 ( x 1 − 1 , y 1 ) (x_1-1,y_1) (x1−1,y1)走到 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)、路径2从上面 ( x 2 − 1 , y 2 ) (x_2-1,y_2) (x2−1,y2)走到、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2),即 f ( x 1 − 1 , y 1 , x 2 − 1 , y 2 ) f(x_1-1,y_1,x_2-1,y_2) f(x1−1,y1,x2−1,y2)
- 路径1从上面 ( x 1 − 1 , y 1 ) (x_1-1,y_1) (x1−1,y1)走到 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)、路径2从左面 ( x 2 , y 2 − 1 ) (x_2,y_2-1) (x2,y2−1)走到、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2),即 f ( x 1 − 1 , y 1 , x 2 , y 2 − 1 ) f(x_1-1,y_1,x_2,y_2-1) f(x1−1,y1,x2,y2−1)
- 路径1从上面 ( x 1 , y 1 − 1 ) (x_1,y_1-1) (x1,y1−1)走到 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)、路径2从上面 ( x 2 − 1 , y 2 ) (x_2-1,y_2) (x2−1,y2)走到、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2),即 f ( x 1 , y 1 − 1 , x 2 − 1 , y 2 ) f(x_1,y_1-1,x_2-1,y_2) f(x1,y1−1,x2−1,y2)
- 路径1从上面 ( x 1 , y 1 − 1 ) (x_1,y_1-1) (x1,y1−1)走到 ( x 1 , y 1 ) (x_1,y_1) (x1,y1)、路径2从左面 ( x 2 , y 2 − 1 ) (x_2,y_2-1) (x2,y2−1)走到、 ( x 2 , y 2 ) (x_2,y_2) (x2,y2),即 f ( x 1 , y 1 − 1 , x 2 , y 2 − 1 ) f(x_1,y_1-1,x_2,y_2-1) f(x1,y1−1,x2,y2−1)
- 走到不同位置,取两个位置上的数。应该取上面 4 4 4种情况的最大值,再加上 w ( x 1 , y 1 ) w(x_1,y_1) w(x1,y1)、 w ( x 2 , y 2 ) w(x_2,y_2) w(x2,y2)。
代码实现
#include <iostream>
using namespace std;
const int N = 15;
//f[x1][y1][x2][y2]表示两条路径到达(x1,y1)、(x2,y2)时得的数字之和的最大值
int w[N][N], f[N][N][N][N];
int main()
{
int n, x, y, z;
cin >> n;
while(cin >> x >> y >> z, x || y || z) w[x][y] = z;
for(int x1 = 1; x1 <= n; x1 ++)
for(int y1 = 1; y1 <= n; y1 ++)
for(int x2 = 1; x2 <= n; x2 ++)
for(int y2 = 1; y2 <= n; y2 ++)
{
//求4种情况的最大值
int t = max(max(f[x1 - 1][y1][x2 - 1][y2], f[x1 - 1][y1][x2][y2 - 1]),
max(f[x1][y1 - 1][x2 - 1][y2], f[x1][y1 - 1][x2][y2 - 1]));
if(x1 == x2 && y1 == y2) //走到相同位置,只取一次数
f[x1][y1][x2][y2] = t + w[x1][y1];
else //走到不同位置,取两个位置上的数
f[x1][y1][x2][y2] = t + w[x1][y1] + w[x2][y2];
}
cout << f[n][n][n][n] << endl;
}
本文介绍了一个寻找两条路径,使得从起点到终点收集数值之和最大的算法问题。通过暴力搜索和动态规划两种方法解决该问题,并给出了详细的代码实现。
111

被折叠的 条评论
为什么被折叠?



