两个球员网格遍历游戏

时间:2016-10-01 10:36:01

标签: java algorithm math dynamic-programming greedy

给出M * N网格和网格上两个玩家p1p2的位置。有n个球放在网格上的不同位置。让这些球的位置为B(1), B(2), B(3) ..., B(n)

我们需要计算选择所有球所需的最小曼哈顿距离。如果B(i) B(j)之前i < j被选中,则应按升序选择球。

请考虑以下示例案例:
p1 = (1, 1) p2 = (3, 4) 让我们考虑球的位置 B(1) = (1, 1), B(2) = (2, 1), B(3) = (3, 1), B(4) = (5, 5)
输出将为5,因为p1将首先选择B(1), B(2), B(3)p1将选择B(4)

我的方法
我做了一个贪心 方法并计算了p1p2距给定球B(i)的距离(从i = 1 to n)并将最小值添加到输出中并相应地更新了播放器的位置。
但是这种方法在很多测试用例中都失败了。

P.S:我在过去的一次采访中提到了这个问题,O(n)预计会出现这个问题。

修改:更多的测试用例可以像是p1 = (1,1) p2 = (3,5)
B(1) = (3, 3), B(2) = (1, 1), B(3) = (4, 5), B(4) = (2, 1), B(5) = (4, 3).
在这种情况下,p1会选择B(2), B(4)p2将选择B(1), B(3), B(5)
输出将为8。

p1 = (1,1) p2 = (3,4)
B(1) = (2, 2), B(2) = (3, 2), B(3) = (4, 2), B(4) = (1, 1)
在这种情况下,p1会选择B(4)p2将选择B(1), B(2), B(3)
输出将为5。
注意:当玩家选择一个球时,他会移动到那个位置

P.P.S。经过讨论,我认为没有线性时间解决方案存在来解决这个问题, O(n ^ 2)解决方案是最好的解决方案。

2 个答案:

答案 0 :(得分:4)

我没有线性时间算法。但这是一个n²动态程序:

对于每个时间点(即每个球),你可以选择其中一个球员来接球。我们应该保留的一个有趣信息是此时其他玩家的位置。所以我们的时间状态Ti{P1, P2}和其他玩家的位置组成。现在,我们希望通过计算下表(使用您的第一个示例)逐步计算每个时间点和每个可能状态的最小距离:

             T1   T2   T3   T4
----------+--------------------
P1; P2@p2 |  0
P1; P2@B1 |
P1; P2@B2 |
P1; P2@B3 |
P2; P1@p1 |  5
P2; P1@B1 |
P2; P1@B2 |
P2; P1@B3 |

两个初始值分别是p1B1以及p2B1之间的距离。

从每个州,我们都可以直接进入正确的相邻小区。这相当于将相应的球员移动到新球并将另一个球员保持在其当前位置。成本的变化是当前球与新球之间的距离。

对于每一个新专栏,我们最后都有一个新的参赛作品(对于这两个参赛者)。这意味着其他球员拿到了最后一个球,而当前的球员可以在任何地方。所以我们必须找到当前球员到当前球的所有可能位置的最小距离。我将在本文末尾对此进行可视化。这样,我们可以按列填充整个表:

示例(再次提出您的问题)

p1 = (1, 1)
p2 = (3, 4) 
B(1) = (1, 1)
B(2) = (2, 1)
B(3) = (3, 1)
B(4) = (5, 5)

DP表:

             T1   T2            T3               T4
----------+---------------------------------------------------------
P1; P2@p2 |  0    0+1=2         1+1=2            2+6=8
P1; P2@B1 |       min(5+1)=6    6+1=7            7+6=13
P1; P2@B2 |                     min(6+2,4+2)=6   6+6=12
P1; P2@B3 |                                      min(7+8,5+8,4+7)=11
P2; P1@p1 |  5   5+1=6          6+1=7            7+6=13
P2; P1@B1 |      min(0+4)=4     4+1=5            5+6=11
P2; P1@B2 |                     min(1+3,6+2)=4   4+6=10
P2; P1@B3 |                                      min(2+3,7+8,6+7)=5

最后一列中的最小值 5 (即收集所有球的最小距离为5)。追溯,我们得到:P2 @ B4,P1 @ B3,P1 @ B2,P1 @ B1。

这是承诺的可视化。为清楚起见,省略了最后一列的对角线依赖性:

enter image description here

我不会提供伪代码,因为我很可能会混淆一些索引(导致混淆而不是帮助)。但是您应该能够编写上述描述中的代码。

答案 1 :(得分:1)

这是O(n^2)动态编程的实现,类似于Nico的回答。该功能的想法是:

// Given N positions, return total distance after a move to B(n),
// where p is the position of the player not at B(n-1)
f(n,p): 

  // at the end, choose between player on prev B and the other
  if n == N-1:
    return min(d(p,B[n]), d(B[n-1],B[n]))

  // otherwise,
  return min(
      // either move player from previous B
      d(B[n-1],B[n]) + f(n+1,p),

      // or move player from other location, p
      d(p,B[n]) + f(n+1,B[n-1])
  )

JavaScript代码,从最后到开头填充矩阵。完成后,我们会选择从一个玩家开始,另一个玩家M[0][N]M[0][N+1]

// Manhattan distance
function d(a,b){
  return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]);
}

var B = [[1,1],[2,1],[3,1],[5,5]], p1 = [1,1], p2 = [3,4];
var N = B.length;

// append initial player positions to B
B.push(p1);
B.push(p2);

// create matrix M[i][j]
// i = current B, j = index of location for player not on B[i-1]
var M = new Array(N);
for (var i=0; i<N; i++){
  M[i] = new Array(N + 2);
}

// at the last B, choose between player on prev B and the other
for (var p=0; p<N+2; p++){
  M[N-1][p] = Math.min(d(B[p],B[N-1]), d(B[N-2],B[N-1]));
}

// either move player from prev B, or from other position, p
for (var i=N-2; i>0; i--){
  for (var p=0; p<N+2; p++){
    M[i][p] = Math.min(d(B[i-1],B[i]) + M[i+1][p],
                       d(B[p],B[i]) + M[i+1][i-1]);
  }
}

// on the first B, choose between the first and second players
M[0][N] = d(B[N],B[0]) + M[1][N+1];
M[0][N+1] = d(B[N+1],B[0]) + M[1][N];

for (var i=0; i<N; i++)
  console.log(JSON.stringify(M[i]));