我正在尝试解决类似于此problem at GeeksforGeeks的问题,但却有所不同:
给定一个矩形的2-d网格,每个单元格中都有一些硬币值,任务是从左上角和右下角开始向右或向下,从右下角到左上角向左或向上,最大化拾取的硬币总量。每个单元格中的硬币只能被挑选一次
链接中的解决方案是同时启动两个遍历,但这不会在这里工作。
我该怎么解决这个问题?执行此操作的蛮力方式是枚举所有路径并选择两条路径,以最大化所拾取的硬币总和,但这对于大输入不起作用。
答案 0 :(得分:9)
我们可以通过三个观察来解决这个问题:
首先,我们不是从两个不同的点开始,而是可以反转第二个人的方向,因此问题变成两个人从左上角开始并同时向右下角移动。
其次,如果我们假设两个人将以相同的速度移动,那么这两个人的状态只能由三个参数表示:x1, x2 and y1
。因为我们可以根据他当前的位置(总和x1 + y1
轻松计算出第一个人的移动次数,因为他只能向右或向下移动),所以,我们也可以计算出第二个人的当前位置(y2 = x1 + y1 - x2
)。请记住,两者都需要进行相同数量的步骤才能到达右下方,因此两者在任何给定时间内都会有相同的移动次数。
最后,我们应该注意到,一个人不能访问一个以上的位置,因为每个人可以采取的唯一方向是正确的或向下的。此外,在任何州,每个人的移动次数相等,因此,如果两个人都有访问的位置,他们将同时访问该位置(并且仅在x1 = x2
时)因此,我们可以很容易地计算收集的硬币数量。
根据这些观察结果,可以很容易地将其简化为与OP链接中的问题类似的问题:
从州(x1, x2, y1)
开始,由于每个人只能向右或向下移动,我们将遵循以下状态:
(x1 + 1, x2 + 1, y1) : Both move to the right.
(x1 + 1, x2, y1) : First person move right, second move down
(x1, x2 + 1, y1 + 1) : First move down, second move right
(x1, x2, y1 + 1) : Both move down.
所以,我们有动态编程公式:
dp[x1][x2][y1] = coin[x1][y1] + (x2 != x1 ? coin[x2][y2] : 0 ) + max(dp[x1 + 1][x2 + 1][y1], dp[x1 + 1][x2][y1], dp[x1][x2 + 1][y1 + 1], dp[x1][x2][y1 + 1])
答案 1 :(得分:0)
我不清楚你需要的2次遍历的确切要求,但对于任何给定的遍历,我会建议。使用Dijkstra的算法,但建立它,使得不是确定因子是2个节点之间的连接的长度/权重,而是使其成为网格平方的值。确保检查具有最大值而不是最小值的路径也很重要。
采用这种方法应该使得如果有多种方法到达一个方格(大部分时间都会有),算法将忽略除了累积最大值的路径之外的所有方法,从而减少需要检查的路径数。
例如:
输入:
int arr[R][C] = {{3, 6, 8},
{5, 2, 4},
{5, 1, 20},
{5, 1, 20, 10},
};
开始: (0,0)3
第一步:
P1: (0,0) 3 , (1,1) 2 Total = 5
P2: (0,0) 3 , (1,0) 5 Total = 8
both are still in the running for the best path.
第2步: P1和P2都可以在蛮力方法中进行下一步(2,1)1,你可以让两条路径继续通过图表的其余部分但是在这种方法中我们看到P2的值比P1大,所以没有需要继续使用P1并从那个方块开始继续使用P2。