给定一个由 ‘#’、’.’ 组成的大小为 NXM 的矩阵和 ‘*’。 ‘#’ 表示阻塞的路径,’.’表示可步行的路径,“*”表示您必须收集的点。现在考虑您位于矩阵的左上角。你必须到达矩阵的右下角,然后回到左上角。当您从左上角到右下角移动时,您可以向右或向下行走。当您将右下角移动到左上角时,您可以向左或向上走。任务是找到您在整个旅程中可以获得的最大积分。获得的积分将转换为“.”。即步行路径。
例子:
Input : N = 3, M = 4
****
.##.
.##.
****
Output : 8
Input : N = 9, M = 7
*........
.....**#.
..**...#*
..####*#.
.*.#*.*#.
...#**...
*........
Output : 7
如果您考虑两条路径——一条从 (0, 0) 到 (N – 1, M – 1),另一个从 (N – 1, M – 1) 到 (0, 0) 并收集每条路径中的最大值 *。你可能会得到错误的答案。如果您独立添加两条路径的答案,您将在回溯时再次计算交点。本质上,以相同的路径结束。即使你保留一个访问过的数组,在第一条路径上标记每个 *,你仍然不会得到正确的答案。
考虑以下示例:
如果我们认为是两条独立的路径,那么
* 收集的总数为 7。
而通过以下路径收集的最大点数可以是 8。
每条路径上有 4 个 *。因此,总数 = 8。
因此我们看到最优解不是两条路径独立的最优解之和。一个人的最佳答案并不能保证最佳答案。
因此,我们必须同时计算两条路径。这是必需的,因为路径 2 的答案取决于路径 1 选择的路线。 可以通过考虑从 (0, 0) 到 (N-1, M-1) 的两条路径并在每个位置做出四个决策来同时进行计算(每人两个)。
因此,我们将同时从 (0, 0) 到 (N-1, M-1) 行进两条路径,而不是两个从左上角到右下角以及从右下角到左上角的一条路径,因此在每个step,我们在两条路径上都迈出一步。所以我们的状态将由 (x1, y1, x2, y2) 组成,其中 (x1, y1) 是第一条路径的位置,(x2, y2) 是网格中第二个游客的位置。
注意事项:
1.每一步都可以向右或向下移动,因此我们有4种移动选择(每条路径2种选择)。
2. 如果两条路径都在同一个单元格上(x1 == x2 和 y1 == y2),那么如果该单元格有 *,我们只能将结果加 1。
3. 我们可以通过将状态维度从 4 减少到 3 来降低复杂度。 如果我们知道第一条路径的位置 (x1, y1) 和第二条路径 x2 的 x 坐标,那么我们必须有 x1 + y1 = x2 + y2 因为两条路径在相同的时间内覆盖相同的距离。所以 y2 = x1 + y1 – x2 而我们的状态只取决于 (x1, y1, x2)。
下面是这个方法的实现:
C++
// CPP program to find maximum points that can
// be collected in a journey from top to bottom
// and then back from bottom to top,
#include
#define MAX 5
#define N 5
#define M 5
#define inf 100000
using namespace std;
// Calculating the points at a (row1, col1) &&
// (row2, col2) from path1 && path2
int cost(char grid[][M], int row1, int col1,
int row2, int col2)
{
// If both path is at same cell
if (row1 == row2 && col1 == col2) {
// If the cell contain *, return 1
if (grid[row1][col1] == '*')
return 1;
// else return 0.
return 0;
}
int ans = 0;
// If path 1 contain *, add to answer.
if (grid[row1][col1] == '*')
ans++;
// If path contain *, add to answer.
if (grid[row2][col2] == '*')
ans++;
return ans;
}
// Calculate the maximum points that can be
// collected.
int solve(int n, int m, char grid[][M],
int dp[MAX][MAX][MAX], int row1,
int col1, int row2)
{
int col2 = (row1 + col1) - (row2);
// If both path reach the bottom right cell
if (row1 == n - 1 && col1 == m - 1 &&
row2 == n - 1 && col2 == m - 1)
return 0;
// If moving out of grid
if (row1 >= n || col1 >= m ||
row2 >= n || col2 >= m)
return -1 * inf;
// If already calculated, return the value
if (dp[row1][col1][row2] != -1)
return dp[row1][col1][row2];
// Variable for 4 options.
int ch1 = -1 * inf, ch2 = -1 * inf;
int ch3 = -1 * inf, ch4 = -1 * inf;
// If path 1 is moving right and path 2
// is moving down.
if (grid[row1][col1 + 1] != '#' &&
grid[row2 + 1][col2] != '#')
ch1 = cost(grid, row1, col1 + 1, row2 + 1, col2) +
solve(n, m, grid, dp, row1, col1 + 1, row2 + 1);
// If path 1 is moving right and path 2 is moving
// right.
if (grid[row1][col1 + 1] != '#' &&
grid[row2][col2 + 1] != '#')
ch2 = cost(grid, row1, col1 + 1, row2, col2 + 1) +
solve(n, m, grid, dp, row1, col1 + 1, row2);
// If path 1 is moving down and path 2 is moving right.
if (grid[row1 + 1][col1] != '#' &&
grid[row2][col2 + 1] != '#')
ch3 = cost(grid, row1 + 1, col1, row2, col2 + 1) +
solve(n, m, grid, dp, row1 + 1, col1, row2);
// If path 1 is moving down and path 2 is moving down.
if (grid[row1 + 1][col1] != '#' &&
grid[row2 + 1][col2] != '#')
ch4 = cost(grid, row1 + 1, col1, row2 + 1, col2) +
solve(n, m, grid, dp, row1 + 1, col1, row2 + 1);
// Returning the maximum of 4 options.
return dp[row1][col1][row2] = max({ch1, ch2, ch3, ch4});
}
// Wrapper Function
int wrapper(int n, int m, char grid[N][M])
{
int ans = 0;
int dp[MAX][MAX][MAX];
memset(dp, -1, sizeof dp);
// If last bottom right cell is blcoked
if (grid[n - 1][m - 1] == '#' || grid[0][0] == '#')
ans = -1 * inf;
// If top left cell contain *
if (grid[0][0] == '*')
ans++;
grid[0][0] = '.';
// If bottom right cell contain *
if (grid[n - 1][m - 1] == '*')
ans++;
grid[n - 1][m - 1] = '.';
ans += solve(n, m, grid, dp, 0, 0, 0);
return max(ans, 0);
}
// Driven Program
int main()
{
int n = 5, m = 5;
char grid[N][M] = {
{ '.', '*', '.', '*', '.' },
{ '*', '#', '#', '#', '.' },
{ '*', '.', '*', '.', '*' },
{ '.', '#', '#', '#', '*' },
{ '.', '*', '.', '*', '.' }
};
cout << wrapper(n, m, grid) << endl;
return 0;
}
Python3
# Python3 program to find maximum points
# that can be collected in a journey from
# top to bottom and then back from bottom to top,
MAX = 5
N = 5
M = 5
inf = 100000
# Calculating the points at a (row1, col1) and
# (row2, col2) from path1 and path2
def cost(grid, row1, col1, row2, col2):
# If both path is at same cell
if (row1 == row2 and col1 == col2):
# If the cell contain *, return 1
if (grid[row1][col1] == '*'):
return 1
# else return 0.
return 0
ans = 0
# If path 1 contain *, add to answer.
if (grid[row1][col1] == '*'):
ans += 1
# If path contain *, add to answer.
if (grid[row2][col2] == '*'):
ans += 1
return ans
# Calculate the maximum points that can be
# collected.
def solve(n, m, grid, dp, row1, col1, row2):
col2 = (row1 + col1) - (row2)
# If both path reach the bottom right cell
if (row1 == n - 1 and col1 == m - 1 and
row2 == n - 1 and col2 == m - 1):
return 0
# If moving out of grid
if (row1 >= n or col1 >= m or
row2 >= n or col2 >= m):
return -1 * inf
# If already calculated, return the value
if (dp[row1][col1][row2] != -1):
return dp[row1][col1][row2]
# Variable for 4 options.
ch1 = -1 * inf
ch2 = -1 * inf
ch3 = -1 * inf
ch4 = -1 * inf
# If path 1 is moving right and path 2
# is moving down.
if (col1 + 1 < m and row2 + 1 < n and
grid[row1][col1 + 1] != '#' and
grid[row2 + 1][col2] != '#'):
ch1 = cost(grid, row1, col1 + 1, row2 + 1, col2) + \
solve(n, m, grid, dp, row1, col1 + 1, row2 + 1)
# If path 1 is moving right and path 2
# is moving right.
if (col1 + 1 < m and col2 + 1 < m and
grid[row1][col1 + 1] != '#' and
grid[row2][col2 + 1] != '#'):
ch2 = cost(grid, row1, col1 + 1, row2, col2 + 1) + \
solve(n, m, grid, dp, row1, col1 + 1, row2)
# If path 1 is moving down and path 2
# is moving right.
if (row1 + 1 < n and col2 + 1 < m and
grid[row1 + 1][col1] != '#' and
grid[row2][col2 + 1] != '#'):
ch3 = cost(grid, row1 + 1, col1, row2, col2 + 1) + \
solve(n, m, grid, dp, row1 + 1, col1, row2)
# If path 1 is moving down and path 2 is moving down.
if (row1 + 1 < n and row2 + 1 < n and
grid[row1 + 1][col1] != '#' and
grid[row2 + 1][col2] != '#'):
ch4 = cost(grid, row1 + 1, col1, row2 + 1, col2) + \
solve(n, m, grid, dp, row1 + 1, col1, row2 + 1)
# Returning the maximum of 4 options.
dp[row1][col1][row2] = max(ch1, ch2, ch3, ch4)
return dp[row1][col1][row2]
# Wrapper Function
def wrapper(n, m, grid):
ans = 0
dp = [[[-1] * MAX for i in range(MAX)]
for j in range(MAX)]
# If last bottom right cell is blcoked
if (grid[n - 1][m - 1] == '#' or
grid[0][0] == '#'):
ans = -1 * inf
# If top left cell contain *
if (grid[0][0] == '*'):
ans += 1
grid[0][0] = '.'
# If bottom right cell contain *
if (grid[n - 1][m - 1] == '*'):
ans += 1
grid[n - 1][m - 1] = '.'
ans += solve(n, m, grid, dp, 0, 0, 0)
return max(ans, 0)
# Driver Code
if __name__ == '__main__':
n = 5
m = 5
grid = [[ '.', '*', '.', '*', '.' ],
[ '*', '#', '#', '#', '.' ],
[ '*', '.', '*', '.', '*' ],
[ '.', '#', '#', '#', '*' ],
[ '.', '*', '.', '*', '.' ]]
print(wrapper(n, m, grid))
# This code is contributed by ashutosh450
输出:
8
时间复杂度: O(N^3)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。