用于找到擦除网格中的点所需的最小镜头数的算法

时间:2013-10-09 06:17:09

标签: java algorithm graph-algorithm

我在网站上看到了这个编程难题,并试图解决它。

问题

您将获得一个N x N网格,其中有一些点随机分布。您必须使用以下允许的操作删除这些点

  • 您可以一次性删除一行中的所有点

  • 或者您可以一次性删除列中的所有点。

你必须找到删除所有点所需的最小镜头数。

实施例

在以下网格中,您需要三次拍摄 - 一次水平拍摄,两次垂直拍摄以取消点。

enter image description here

我尝试了一种方法,用点来计算行和列,最小的是答案。但是在特定情况下它会失败,如上例所示。 这样做的方法是什么,或者是否存在类似于我可以参考解决此问题的任何情况?

修改

给出的约束是

1 <= N <= 1000
0 <= x,y <= 10^9
Time Limit: 2 sec

其中n是网格的维度(即nxn),x,y是坐标

3 个答案:

答案 0 :(得分:1)

将2D网格转换为二分图。左侧包含节点表示行,右侧包含节点表示列。对于包含点的每个单元格,假设它的坐标为(x,y),添加链接row_x和column_y的边。建立二分图后,使用匈牙利算法获得最大匹配。因为在二分图中,最大匹配的答案等于最小顶点覆盖,这正是你想要的。

匈牙利算法是O(V * E)算法。有关详细信息,请参阅Hungarian algorithm

有关二分图的更多信息,请参阅Bipartite graph,您可以找到为什么最大匹配等于此处覆盖的最小顶点。

答案 1 :(得分:0)

我会尝试一种详尽的算法。如果你做得对,它并没有听起来那么糟糕。

你已经知道,在最坏的情况下,它需要N次射击(如果你在每一行或每一列射击,它肯定会起作用。)

因此,为了改善更糟糕的情况,您只需要尝试所有可能的列镜头+行镜头的排列,其中总镜头数小于N.例如,如果N = 4,则必须使用非平凡的解决方案be&lt; = 3,所以尝试所有(列,行)镜头:

(0,3)
(1,2)
(2,1)
(3,0)

对于您想拍摄的任何轴(列或行),有(s choose N)种可能性。因此,大N的可能性的总数类似于(N/2) choose N,这对于N&lt; 30无论如何。

我确信有更好的启发式算法,并且可能还有更好的案例算法。

答案 2 :(得分:0)

我认为这里可能会应用递归。我不认为它是有效的,但跟随是一个你可以使用的想法。

从左上角点开始。您有以下方案:

  1. 同一行和同一列中有另一个点。 - &GT;分支到三种可能性

  2. 同一行中有另一个点但不在同一列中。 - &GT;拍摄此行,删除同一行中的所有点并移动到下一个点。

  3. 同一列中有另一个点,但不在同一行.-&gt;拍摄此列,删除同一列中的所有点并移动到下一个点。

  4. 同一列或同一行中没有点。 - &GT;射击行或列,没关系,继续下一个点。

  5. 对于第一种情况,分支必须完成如下操作:

    int minimumNumberOfLines( matrixOfDots ) {
      return min( 1 + minimumNumberOfLines( with row shot ),1 + minimumNumberOfLines( with col shot ), 2 + minimumNumberOfLines( with row and column shot ) ). 
    }